Type discussed here only strings, int, datetime, text data types not discussed, whether to save space because the data type is given
Before writing this article, I have always thought that this problem is very simple, look at the data page on the line, but then read, read, modify a few times
Find data pages need to SQSERVER very familiar with before you can know SQLSERVER interior space occupied by what, I hope you look at the following article before you continue to read
Before you read on, please look at the following article
char nchar varchar nvarchar distinction of : char nchar varchar nvarchar length occupied by data type
SQL Server physical memory pages Bank of China
SQL Server errors 30 to talk about the three errors -Day6- NULL bitmap
Table SQL Server2008 heap storage structure, the overflow line
If you do not see the above article, for people who are just getting started may only be a smattering of knowledge, in order to length of the article not too long, I will not explain some important terms in article
Look at the article given it o (∩_∩) o
First create the following table and insert the test data
Establish a DBCCResult table, save DBCC IND results
View tables in each case
VARCHAR type of situation
testnullvarchar 表
Data pages
1 Slot 0 Offset 0x60 Length 11 2 3 Record Type = PRIMARY_RECORD Record Attributes = NULL_BITMAP 4 Memory Dump @0x0A16C060 5 6 00000000: 10000800 01000000 0200fe†††††††††††††........... 7 8 Slot 0 Column 0 Offset 0x4 Length 4 9 10 id = 1 11 NAME = [NULL] 12 13 Slot 1 Offset 0x6b Length 17 14 15 Record Type = PRIMARY_RECORD Record Attributes = NULL_BITMAP VARIABLE_COLUMNS 16 17 Memory Dump @0x0A16C06B 18 19 00000000: 30000800 02000000 0200fc01 001100c4 †0............... 20 00000010: e3 †††††††††††††††††††††††††††††††††††. 21 22 Slot 1 Column 0 Offset 0x4 Length 4 23 24 id = 2 25 26 Slot 1 Column 1 Offset 0xf Length 2 27 28 NAME = you
We look at the first line of the record length of 11 how get out
In SQL Server page BOC physical storage of data rows each segment are explained in
2 -byte line header stores information of the state A and state B (2 bytes row header)
2 -byte fixed-length storage size, as a row of data types varchar these are not fixed length (2 bytes for length of fixed length columns)
SQLSERVER需要知道int、datetime、decimal这些固定长度数据类型的大小
2个字节的列数,用来存储这个表一共有多少列(2 bytes for number of columns in the table)
1个字节的null bitmap,(1 byte for null bitmap)
4个字节存储int型数据(4 bytes for int (1st column))
2+2+2+1+4=11
换言之,第一行记录中name字段不占用任何空间,因为第一行记录中的name值为NULL
-------------------------------------------------------------------------------------------------------
我们看第二行记录长度17怎麽得出来的
2个字节行标头存储了状态A和状态B的信息(2 bytes row header)
2个字节存储固定长度大小,因为一行记录了有varchar这些不固定长度的数据类型(2 bytes for length of fixed length columns)
SQLSERVER需要知道int、datetime、decimal这些固定长度数据类型的大小
2个字节的列数,用来存储这个表一共有多少列(2 bytes for number of columns in the table)
1个字节的null bitmap,(1 byte for null bitmap)
4个字节存储int型数据(4 bytes for int (1st column))
2个字节存储数据行中的可变长度列数量,统计数据行中一共有多少列是nvarchar ,varchar类型的列( 2 bytes for number of variable length columns in the table)
2个字节存储可变长度偏移阵列,可变长度偏移阵列的公式
2*表格中可变长度数据类型的列数量,这个表只有一列varchar,所以2*1=2,为什麽要有可变长度偏移阵列?我估计是因为可变长度的数据类型
存储的数据是不固定的,所以要预留一些位置,当update varchar值的时候有足够的位置(2 bytes for name column offset)
2个字节存储name列的值,为什麽用两个字节大家可以看一下char nchar varchar nvarchar的区别 2 bytes for name (你)
2+2+2+1+4+2+2+2=17
前11个字节跟第一行记录是一样的长度,关键在于后面的6个字节,在这6个字节中只有2个字节实际存储数据的
为什麽在第一行记录里没有这4个字节呢?
2个字节存储数据行中的可变长度列数量
2个字节存储可变长度偏移阵列
想法:
我估计是因为,第一行记录中没有一个可变长度数据类型的列是有数据的,全部都是NULL,
既然这样SQLSERVER就没有必要再用4个字节去存储2个字节存储数据行中的可变长度列数量和2个字节存储可变长度偏移阵列
我们来验证一下这个想法:
代码如下:
数据页内容
我们看第一行记录长度19怎麽得出来的
2个字节行标头存储了状态A和状态B的信息
2个字节存储固定长度大小
2个字节的列数
1个字节的null bitmap
4个字节存储int型数据
2个字节存储数据行中的可变长度列数量
4个字节存储可变长度偏移阵列 2*2=4
2个字节存储name列的值
2+2+2+1+4+2+4+2=19
也就是说,一行记录中全部的可变长度数据列的数据全部为NULL,才不会有这4个字节
2个字节存储数据行中的可变长度列数量
2个字节存储可变长度偏移阵列
其实SQLSERVER也做了一下标记,区分开一行记录中全部的可变长度类型列的数据全部为NULL还是一些为NULL一些不为NULL,还是全部不为NULL
这里可以在行记录属性中看出,testnullvarchar表的第一行和第二行
第一行NULL_BITMAP表明一行记录中全部的可变长度类型列的数据全部为NULL
第二行NULL_BITMAP VARIABLE_COLUMNS表明一些为NULL一些不为NULL或者全部不为NULL
小结:
VARCHAR类型NULL值不占用任何空间
testnotnullvarchar表
数据页内容
1 Slot 0 Offset 0x60 Length 11 2 3 Record Type = PRIMARY_RECORD Record Attributes = NULL_BITMAP 4 Memory Dump @0x0855C060 5 6 00000000: 10000800 01000000 0200fc†††††††††††††........... 7 8 Slot 0 Column 0 Offset 0x4 Length 4 9 10 id = 1 11 NAME = [NULL] 12 13 Slot 1 Offset 0x6b Length 17 14 15 Record Type = PRIMARY_RECORD Record Attributes = NULL_BITMAP VARIABLE_COLUMNS 16 17 Memory Dump @0x0855C06B 18 19 00000000: 30000800 02000000 0200fc01 001100c4 †0............... 20 00000010: e3†††††††††††††††††††††††††††††††††††. 21 22 Slot 1 Column 0 Offset 0x4 Length 4 23 24 id = 2 25 26 Slot 1 Column 1 Offset 0xf Length 2 27 28 NAME = 你
testnotnullvarchar表的数据页和testnullvarchar表的数据页对比一下
看到上面的对比图我也不再对testnotnullvarchar表做详细分析了
情况跟testnullvarchar表是一样的
只有一个地方不一样,就是LEN()函数
小结:
对于varchar数据类型,无论是空字符串还是NULL值都不占用任何空间
CHAR类型的情况
testnullchar表
数据页内容
1 Slot 0 Offset 0x60 Length 31 2 3 Record Type = PRIMARY_RECORD Record Attributes = NULL_BITMAP 4 Memory Dump @0x0A27C060 5 6 00000000: 10001c00 01000000 00000000 00000000 †................ 7 00000010: 00000000 00000000 00000000 0200fe††††............... 8 9 Slot 0 Column 0 Offset 0x4 Length 4 10 11 id = 1 12 NAME = [NULL] 13 14 Slot 1 Offset 0x7f Length 31 15 16 Record Type = PRIMARY_RECORD Record Attributes = NULL_BITMAP 17 Memory Dump @0x0A27C07F 18 19 00000000: 10001c00 02000000 c4e32020 20202020 †.......... 20 00000010: 20202020 20202020 20202020 0200fc†††† ... 21 22 Slot 1 Column 0 Offset 0x4 Length 4 23 24 id = 2 25 26 Slot 1 Column 1 Offset 0x8 Length 20 27 28 NAME = 你
我们看第一行记录长度31怎麽得出来的
2个字节行标头存储了状态A和状态B的信息(2 bytes row header)
2个字节存储固定长度大小,因为一行记录了有varchar这些不固定长度的数据类型(2 bytes for length of fixed length columns)
4个字节存储int型数据(4 bytes for int (1st column))
2个字节的列数,用来存储这个表一共有多少列(2 bytes for number of columns in the table)
1个字节的null bitmap,(1 byte for null bitmap)
20个字节存储name列的值,为什麽用20个字节大家可以看一下char nchar varchar nvarchar的区别 20 bytes for char(20) (2nd column)
2+2+4+2+1+20=31
换言之,第一行记录中name字段是否为NULL,都占用20个字节的空间
-----------------------------------------------------------------------------------------
我们看第二行记录长度31怎麽得出来的
实际上第二行记录和第一行记录是一样的,只不过第二行记录里的name列存储了实际的值“你”,
而不管存储的值大小如何都占用20个字节
2个字节行标头存储了状态A和状态B的信息(2 bytes row header)
2个字节存储固定长度大小,因为一行记录了有varchar这些不固定长度的数据类型(2 bytes for length of fixed length columns)
4个字节存储int型数据(4 bytes for int (1st column))
2个字节的列数,用来存储这个表一共有多少列(2 bytes for number of columns in the table)
1个字节的null bitmap,(1 byte for null bitmap)
20个字节存储name列的值,为什麽用20个字节大家可以看一下char nchar varchar nvarchar的区别 20 bytes for char(20) (2nd column)
2+2+4+2+1+20=31
小结:
CHAR类型NULL值会占用空间,所占用空间大小取决于建表时候指定的char数据类型的大小
例如:
1 --允许空,char类型 2 CREATE TABLE testnullchar(id INT,NAME CHAR(20) NULL) 3 GO
指定char为20,那么就占用20个字节的空间
testnotnullchar表
数据页内容
1 Slot 0 Offset 0x60 Length 31 2 3 Record Type = PRIMARY_RECORD Record Attributes = NULL_BITMAP 4 Memory Dump @0x0A01C060 5 6 00000000: 10001c00 01000000 20202020 20202020 †........ 7 00000010: 20202020 20202020 20202020 0200fc†††† ... 8 9 Slot 0 Column 0 Offset 0x4 Length 4 10 11 id = 1 12 13 Slot 0 Column 1 Offset 0x8 Length 20 14 15 NAME = 16 17 Slot 1 Offset 0x7f Length 31 18 19 Record Type = PRIMARY_RECORD Record Attributes = NULL_BITMAP 20 Memory Dump @0x0A01C07F 21 22 00000000: 10001c00 02000000 c4e32020 20202020 †.......... 23 00000010: 20202020 20202020 20202020 0200fc†††† ... 24 25 Slot 1 Column 0 Offset 0x4 Length 4 26 27 id = 2 28 29 Slot 1 Column 1 Offset 0x8 Length 20 30 31 NAME = 你
testnotnullchar表的数据页和testnullchar表的数据页对比一下
看到上面的对比图我也不再对testnotnullchar表做详细分析了
情况跟testnullchar表是一样的
只有两个地方不一样,testnotnullchar表的第一行记录的name字段存储的是空字符串
而testnullchar表的第一行记录的name字段存储的是NULL
不过无论是空字符串还是NULL都占用了31个字节
LEN()函数返回的值不一样,这里跟varchar类型的情况也是一样的
跟varchar类型不一样的是,testnotnullchar表的第一行记录的name字段存储的是空字符串,而testnullchar表的第一行记录的name字段存储的是NULL
varchar情况,testnotnullvarchar表和testnullvarchar表的第一行记录的name字段存储的都是NULL
而奇怪的是testnotnullvarchar表返回的不是NULL值,而是空字符串
小结:
对于char数据类型,无论是空字符串还是NULL值都占用空间,所占用空间大小取决于建表时候指定的char数据类型的大小
例如:
1 --允许空,char类型 2 CREATE TABLE testnullchar(id INT,NAME CHAR(20) NULL) 3 GO
The char is 20, then take up 20 bytes of space
to sum up
For varchar data type, whether it is an empty string or NULL value does not take up any space
For char data type, whether it is an empty string or NULL values are space, depending on the size of the space to build the table when the specified char data type size occupied
From the above experimental point of view, whether the space savings is determined according to the data type is not NULL or an empty string if
Leaving aside the type of data does not make sense to compare, as DATETIME data type column filled NULL values and VARCHAR data type column filled NULL value,
Two NULL values, which is the larger? Without the two data types were analyzed individually compare these two NULL values, this comparison does not make sense
But also unequal, because the two data types had nothing to do, a type datetime, varchar type is a
The same is true of char and varchar
Compare only makes sense with a data type, just as are the varchar data type, an empty string and NULL values are compared
Char data type are the same, the empty string, and the NULL value is compared
So usually you want to have a certain understanding of the SQLSERVER data types, in order to have a rough grasp of the use of table space system
If wrong place, welcome Paizhuan o (∩_∩) o