SQLSERVER NULL和空字符串的區別 使用NULL是否節省空間

SQLSERVER NULL和空字符串的區別 使用NULL是否節省空間

這裏只討論字符串類型,int、datetime、text這些數據類型就不討論了,由於是否節省空間是根據數據類型來定的html

在寫這篇文章以前,本人一直覺得這個問題很簡單的,看一下數據頁就好了,可是後來寫着寫着,也修改了幾回web

發現須要對SQSERVER的數據頁內容很熟悉您才能知道SQLSERVER內部空間佔用是怎樣的,但願你們在繼續往下看以前先看一下下面文章ide

在往下看以前請各位先看一下下面的文章函數

char nchar varchar nvarchar的區別  :char nchar varchar nvarchar數據類型所佔用長度測試

SQL Server頁中行物理存儲spa

SQL Server誤區30日談-Day6-有關NULL位圖的三個誤區3d

SQL Server2008存儲結構之堆表、行溢出code

SQLSERVER中NULL位圖的做用orm

若是不看上面的文章,對於剛入門的人來講可能只會是隻知其一;不知其二,爲了文章的篇幅不要過長,我就在文章裏不解釋一些重要名詞了htm

你們看一下給出的文章就能夠了o(∩_∩)o


先創建下面表格並插入測試數據

 1 USE [pratice]
 2 GO
 3 
 4 
 5 --容許空,varchar類型
 6 CREATE TABLE testnullvarchar(id INT ,NAME VARCHAR(20) NULL)
 7 GO
 8 --容許空,char類型
 9 CREATE TABLE testnullchar(id INT,NAME CHAR(20) NULL)
10 GO
11 --不容許空,varchar類型
12 CREATE TABLE testnotnullvarchar(id INT ,NAME VARCHAR(20) NOT NULL)
13 GO
14 --不容許空,char類型
15 CREATE TABLE testnotnullchar(id INT ,NAME CHAR(20) NOT NULL)
16 GO
17 
18 --插入數據
19 INSERT INTO [dbo].[testnullvarchar] ( [id],[Name] )
20 SELECT 1 ,NULL UNION ALL
21 SELECT 2,''
22 GO
23 
24 INSERT INTO [dbo].[testnullchar] ( [id],[Name] )
25 SELECT 1,NULL UNION ALL
26 SELECT 2,''
27 GO
28 
29 INSERT INTO [dbo].[testnotnullchar] ( [id],[NAME] )
30 SELECT 1,'' UNION ALL
31 SELECT 2,''
32 GO
33 
34 INSERT INTO [dbo].[testnotnullvarchar] ( [id],[NAME] )
35 SELECT 1,'' UNION ALL
36 SELECT 2,''
37 GO
38 
39 SELECT * FROM testnullvarchar
40 SELECT * FROM testnullchar
41 SELECT * FROM testnotnullchar
42 SELECT * FROM testnotnullvarchar
View Code

 

創建一個DBCCResult表,保存DBCC IND的結果

 1 CREATE TABLE DBCCResult (
 2 PageFID NVARCHAR(200),
 3 PagePID NVARCHAR(200),
 4 IAMFID NVARCHAR(200),
 5 IAMPID NVARCHAR(200),
 6 ObjectID NVARCHAR(200),
 7 IndexID NVARCHAR(200),
 8 PartitionNumber NVARCHAR(200),
 9 PartitionID NVARCHAR(200),
10 iam_chain_type NVARCHAR(200),
11 PageType NVARCHAR(200),
12 IndexLevel NVARCHAR(200),
13 NextPageFID NVARCHAR(200),
14 NextPagePID NVARCHAR(200),
15 PrevPageFID NVARCHAR(200),
16 PrevPagePID NVARCHAR(200)
17 )
18 GO
View Code

 


查看各張表的狀況

 

VARCHAR類型的狀況

testnullvarchar表

 1 --TRUNCATE TABLE DBCCResult
 2 INSERT INTO DBCCResult EXEC ('DBCC IND(pratice,testnullvarchar,-1) ')
 3 
 4 SELECT * FROM [dbo].[DBCCResult] ORDER BY [PageType] DESC 
 5 
 6 
 7 DBCC TRACEON(3604,-1)
 8 GO
 9 DBCC PAGE([pratice],1,8370,3)
10 GO
11 
12 
13     
14 SELECT LEN(name) FROM testnullvarchar WHERE [id]=1
View Code

數據頁內容

 1 DBCC 執行完畢。若是 DBCC 輸出了錯誤信息,請與系統管理員聯繫。
 2 
 3 PAGE: (1:8370)
 4 
 5 
 6 BUFFER:
 7 
 8 
 9 BUF @0x03CF4E64
10 
11 bpage = 0x16F16000                   bhash = 0x00000000                   bpageno = (1:8370)
12 bdbid = 5                            breferences = 0                      bUse1 = 9390
13 bstat = 0x2c0000b                    blog = 0x32159bb                     bnext = 0x00000000
14 
15 PAGE HEADER:
16 
17 
18 Page @0x16F16000
19 
20 m_pageId = (1:8370)                  m_headerVersion = 1                  m_type = 1
21 m_typeFlagBits = 0x4                 m_level = 0                          m_flagBits = 0x8000
22 m_objId (AllocUnitId.idObj) = 521    m_indexId (AllocUnitId.idInd) = 256  
23 Metadata: AllocUnitId = 72057594072072192                                 
24 Metadata: PartitionId = 72057594059882496                                 Metadata: IndexId = 0
25 Metadata: ObjectId = 1207675350      m_prevPage = (0:0)                   m_nextPage = (0:0)
26 pminlen = 8                          m_slotCnt = 2                        m_freeCnt = 8064
27 m_freeData = 124                     m_reservedCnt = 0                    m_lsn = (3045:22651:20)
28 m_xactReserved = 0                   m_xdesId = (0:0)                     m_ghostRecCnt = 0
29 m_tornBits = 0                       
30 
31 Allocation Status
32 
33 GAM (1:2) = ALLOCATED                SGAM (1:3) = ALLOCATED               
34 PFS (1:8088) = 0x61 MIXED_EXT ALLOCATED  50_PCT_FULL                      DIFF (1:6) = CHANGED
35 ML (1:7) = NOT MIN_LOGGED            
36 
37 Slot 0 Offset 0x60 Length 11
38 
39 Record Type = PRIMARY_RECORD         Record Attributes =  NULL_BITMAP     
40 Memory Dump @0x0A16C060
41 
42 00000000:   10000800 01000000 0200fe†††††††††††††...........              
43 
44 Slot 0 Column 0 Offset 0x4 Length 4
45 
46 id = 1                               
47 NAME = [NULL]                        
48 
49 Slot 1 Offset 0x6b Length 17
50 
51 Record Type = PRIMARY_RECORD         Record Attributes =  NULL_BITMAP VARIABLE_COLUMNS
52 
53 Memory Dump @0x0A16C06B
54 
55 00000000:   30000800 02000000 0200fc01 001100c4 †0...............         
56 00000010:   e3†††††††††††††††††††††††††††††††††††.                        
57 
58 Slot 1 Column 0 Offset 0x4 Length 4
59 
60 id = 2                               
61 
62 Slot 1 Column 1 Offset 0xf Length 2
63 
64 NAME =65 
66 
67 DBCC 執行完畢。若是 DBCC 輸出了錯誤信息,請與系統管理員聯繫。
View Code

 

 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 =

咱們看第一行記錄長度11怎麼得出來的

SQL Server頁中行物理存儲裏對數據行的各段進行了解釋

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+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個字節存儲可變長度偏移陣列

咱們來驗證一下這個想法:

代碼以下:

 1 USE [pratice]
 2 GO
 3 --
 4 CREATE TABLE testnullandnotnullvarchar(id INT ,NAME1 VARCHAR(20) NULL,NAME2 VARCHAR(20) NULL)
 5 GO
 6 
 7 --插入數據
 8 INSERT INTO [dbo].[testnullandnotnullvarchar] ( [id],[Name1],[NAME2] )
 9 SELECT 1 ,NULL,''
10 GO
11 
12 SELECT * FROM testnullandnotnullvarchar
13 -----------------------------------------------------------
14 --TRUNCATE TABLE DBCCResult
15 INSERT INTO DBCCResult EXEC ('DBCC IND(pratice,testnullandnotnullvarchar,-1) ')
16 
17 SELECT * FROM [dbo].[DBCCResult] ORDER BY [PageType] DESC 
18 
19 
20 DBCC TRACEON(3604,-1)
21 GO
22 DBCC PAGE([pratice],1,15656,3)
23 GO
View Code

數據頁內容

 1 DBCC 執行完畢。若是 DBCC 輸出了錯誤信息,請與系統管理員聯繫。
 2 
 3 PAGE: (1:15656)
 4 
 5 
 6 BUFFER:
 7 
 8 
 9 BUF @0x03D42838
10 
11 bpage = 0x196A6000                   bhash = 0x00000000                   bpageno = (1:15656)
12 bdbid = 5                            breferences = 0                      bUse1 = 32718
13 bstat = 0xc0000b                     blog = 0xbbbbbbbb                    bnext = 0x00000000
14 
15 PAGE HEADER:
16 
17 
18 Page @0x196A6000
19 
20 m_pageId = (1:15656)                 m_headerVersion = 1                  m_type = 1
21 m_typeFlagBits = 0x4                 m_level = 0                          m_flagBits = 0x8000
22 m_objId (AllocUnitId.idObj) = 531    m_indexId (AllocUnitId.idInd) = 256  
23 Metadata: AllocUnitId = 72057594072727552                                 
24 Metadata: PartitionId = 72057594060537856                                 Metadata: IndexId = 0
25 Metadata: ObjectId = 1383675977      m_prevPage = (0:0)                   m_nextPage = (0:0)
26 pminlen = 8                          m_slotCnt = 1                        m_freeCnt = 8075
27 m_freeData = 115                     m_reservedCnt = 0                    m_lsn = (3045:22996:18)
28 m_xactReserved = 0                   m_xdesId = (0:0)                     m_ghostRecCnt = 0
29 m_tornBits = 0                       
30 
31 Allocation Status
32 
33 GAM (1:2) = ALLOCATED                SGAM (1:3) = ALLOCATED               
34 PFS (1:8088) = 0x61 MIXED_EXT ALLOCATED  50_PCT_FULL                      DIFF (1:6) = CHANGED
35 ML (1:7) = NOT MIN_LOGGED            
36 
37 Slot 0 Offset 0x60 Length 19
38 
39 Record Type = PRIMARY_RECORD         Record Attributes =  NULL_BITMAP VARIABLE_COLUMNS
40 
41 Memory Dump @0x0855C060
42 
43 00000000:   30000800 01000000 0300fa02 001100130...............         
44 00000010:   00c4e3†††††††††††††††††††††††††††††††...                      
45 
46 Slot 0 Column 0 Offset 0x4 Length 4
47 
48 id = 1                               
49 NAME1 = [NULL]                       
50 
51 Slot 0 Column 2 Offset 0x11 Length 2
52 
53 NAME2 =54 
55 
56 DBCC 執行完畢。若是 DBCC 輸出了錯誤信息,請與系統管理員聯繫。
View Code

咱們看第一行記錄長度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 --TRUNCATE TABLE DBCCResult
 2 INSERT INTO DBCCResult EXEC ('DBCC IND(pratice,testnotnullvarchar,-1) ')
 3 
 4 SELECT * FROM [dbo].[DBCCResult] ORDER BY [PageType] DESC 
 5 
 6 
 7 DBCC TRACEON(3604,-1)
 8 GO
 9 DBCC PAGE([pratice],1,14495,3)
10 GO
11 
12     
13 SELECT LEN(name) FROM testnotnullvarchar WHERE [id]=1
View Code

數據頁內容

 1 DBCC 執行完畢。若是 DBCC 輸出了錯誤信息,請與系統管理員聯繫。
 2 
 3 PAGE: (1:14495)
 4 
 5 
 6 BUFFER:
 7 
 8 
 9 BUF @0x03D4258C
10 
11 bpage = 0x196D2000                   bhash = 0x00000000                   bpageno = (1:14495)
12 bdbid = 5                            breferences = 0                      bUse1 = 38447
13 bstat = 0xc0000b                     blog = 0xbbbbbbbb                    bnext = 0x00000000
14 
15 PAGE HEADER:
16 
17 
18 Page @0x196D2000
19 
20 m_pageId = (1:14495)                 m_headerVersion = 1                  m_type = 1
21 m_typeFlagBits = 0x4                 m_level = 0                          m_flagBits = 0x8000
22 m_objId (AllocUnitId.idObj) = 532    m_indexId (AllocUnitId.idInd) = 256  
23 Metadata: AllocUnitId = 72057594072793088                                 
24 Metadata: PartitionId = 72057594060603392                                 Metadata: IndexId = 0
25 Metadata: ObjectId = 1399676034      m_prevPage = (0:0)                   m_nextPage = (0:0)
26 pminlen = 8                          m_slotCnt = 2                        m_freeCnt = 8064
27 m_freeData = 124                     m_reservedCnt = 0                    m_lsn = (3045:23036:20)
28 m_xactReserved = 0                   m_xdesId = (0:0)                     m_ghostRecCnt = 0
29 m_tornBits = 0                       
30 
31 Allocation Status
32 
33 GAM (1:2) = ALLOCATED                SGAM (1:3) = ALLOCATED               
34 PFS (1:8088) = 0x61 MIXED_EXT ALLOCATED  50_PCT_FULL                      DIFF (1:6) = CHANGED
35 ML (1:7) = NOT MIN_LOGGED            
36 
37 Slot 0 Offset 0x60 Length 11
38 
39 Record Type = PRIMARY_RECORD         Record Attributes =  NULL_BITMAP     
40 Memory Dump @0x0855C060
41 
42 00000000:   10000800 01000000 0200fc†††††††††††††...........              
43 
44 Slot 0 Column 0 Offset 0x4 Length 4
45 
46 id = 1                               
47 NAME = [NULL]                        
48 
49 Slot 1 Offset 0x6b Length 17
50 
51 Record Type = PRIMARY_RECORD         Record Attributes =  NULL_BITMAP VARIABLE_COLUMNS
52 
53 Memory Dump @0x0855C06B
54 
55 00000000:   30000800 02000000 0200fc01 001100c4 †0...............         
56 00000010:   e3†††††††††††††††††††††††††††††††††††.                        
57 
58 Slot 1 Column 0 Offset 0x4 Length 4
59 
60 id = 2                               
61 
62 Slot 1 Column 1 Offset 0xf Length 2
63 
64 NAME =65 
66 
67 DBCC 執行完畢。若是 DBCC 輸出了錯誤信息,請與系統管理員聯繫。
View Code
 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 --TRUNCATE TABLE DBCCResult
 2 INSERT INTO DBCCResult EXEC ('DBCC IND(pratice,testnullchar,-1) ')
 3 
 4 SELECT * FROM [dbo].[DBCCResult] ORDER BY [PageType] DESC 
 5 
 6 
 7 DBCC TRACEON(3604,-1)
 8 GO
 9 DBCC PAGE([pratice],1,8353,3)
10 GO
11 
12 
13 
14 SELECT LEN(name) FROM testnullchar WHERE [id]=1
View Code

數據頁內容

 1 DBCC 執行完畢。若是 DBCC 輸出了錯誤信息,請與系統管理員聯繫。
 2 
 3 PAGE: (1:8353)
 4 
 5 
 6 BUFFER:
 7 
 8 
 9 BUF @0x03CF68D0
10 
11 bpage = 0x16FA8000                   bhash = 0x00000000                   bpageno = (1:8353)
12 bdbid = 5                            breferences = 0                      bUse1 = 39861
13 bstat = 0x2c0000b                    blog = 0x59bbbbbb                    bnext = 0x00000000
14 
15 PAGE HEADER:
16 
17 
18 Page @0x16FA8000
19 
20 m_pageId = (1:8353)                  m_headerVersion = 1                  m_type = 1
21 m_typeFlagBits = 0x4                 m_level = 0                          m_flagBits = 0x8000
22 m_objId (AllocUnitId.idObj) = 533    m_indexId (AllocUnitId.idInd) = 256  
23 Metadata: AllocUnitId = 72057594072858624                                 
24 Metadata: PartitionId = 72057594060668928                                 Metadata: IndexId = 0
25 Metadata: ObjectId = 1415676091      m_prevPage = (0:0)                   m_nextPage = (0:0)
26 pminlen = 28                         m_slotCnt = 2                        m_freeCnt = 8030
27 m_freeData = 158                     m_reservedCnt = 0                    m_lsn = (3045:23074:20)
28 m_xactReserved = 0                   m_xdesId = (0:0)                     m_ghostRecCnt = 0
29 m_tornBits = 0                       
30 
31 Allocation Status
32 
33 GAM (1:2) = ALLOCATED                SGAM (1:3) = ALLOCATED               
34 PFS (1:8088) = 0x61 MIXED_EXT ALLOCATED  50_PCT_FULL                      DIFF (1:6) = CHANGED
35 ML (1:7) = NOT MIN_LOGGED            
36 
37 Slot 0 Offset 0x60 Length 31
38 
39 Record Type = PRIMARY_RECORD         Record Attributes =  NULL_BITMAP     
40 Memory Dump @0x0A27C060
41 
42 00000000:   10001c00 01000000 00000000 00000000 †................         
43 00000010:   00000000 00000000 00000000 0200fe††††...............          
44 
45 Slot 0 Column 0 Offset 0x4 Length 4
46 
47 id = 1                               
48 NAME = [NULL]                        
49 
50 Slot 1 Offset 0x7f Length 31
51 
52 Record Type = PRIMARY_RECORD         Record Attributes =  NULL_BITMAP     
53 Memory Dump @0x0A27C07F
54 
55 00000000:   10001c00 02000000 c4e32020 20202020 †..........               
56 00000010:   20202020 20202020 20202020 0200fc††††            ...          
57 
58 Slot 1 Column 0 Offset 0x4 Length 4
59 
60 id = 2                               
61 
62 Slot 1 Column 1 Offset 0x8 Length 20
63 
64 NAME =65 
66 
67 DBCC 執行完畢。若是 DBCC 輸出了錯誤信息,請與系統管理員聯繫。
View Code
 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 --TRUNCATE TABLE DBCCResult
 2 INSERT INTO DBCCResult EXEC ('DBCC IND(pratice,testnotnullchar,-1) ')
 3 
 4 SELECT * FROM [dbo].[DBCCResult] ORDER BY [PageType] DESC 
 5 
 6 
 7 DBCC TRACEON(3604,-1)
 8 GO
 9 DBCC PAGE([pratice],1,37266,3)
10 GO
11 
12 
13 
14 SELECT LEN(name) FROM testnotnullchar WHERE [id]=1
View Code

數據頁內容

 1 DBCC 執行完畢。若是 DBCC 輸出了錯誤信息,請與系統管理員聯繫。
 2 
 3 PAGE: (1:37266)
 4 
 5 
 6 BUFFER:
 7 
 8 
 9 BUF @0x03D669F0
10 
11 bpage = 0x1A500000                   bhash = 0x00000000                   bpageno = (1:37266)
12 bdbid = 5                            breferences = 0                      bUse1 = 42107
13 bstat = 0xc0000b                     blog = 0x9bbbbbbb                    bnext = 0x00000000
14 
15 PAGE HEADER:
16 
17 
18 Page @0x1A500000
19 
20 m_pageId = (1:37266)                 m_headerVersion = 1                  m_type = 1
21 m_typeFlagBits = 0x4                 m_level = 0                          m_flagBits = 0x8000
22 m_objId (AllocUnitId.idObj) = 534    m_indexId (AllocUnitId.idInd) = 256  
23 Metadata: AllocUnitId = 72057594072924160                                 
24 Metadata: PartitionId = 72057594060734464                                 Metadata: IndexId = 0
25 Metadata: ObjectId = 1431676148      m_prevPage = (0:0)                   m_nextPage = (0:0)
26 pminlen = 28                         m_slotCnt = 2                        m_freeCnt = 8030
27 m_freeData = 158                     m_reservedCnt = 0                    m_lsn = (3045:23137:20)
28 m_xactReserved = 0                   m_xdesId = (0:0)                     m_ghostRecCnt = 0
29 m_tornBits = 0                       
30 
31 Allocation Status
32 
33 GAM (1:2) = ALLOCATED                SGAM (1:3) = ALLOCATED               
34 PFS (1:32352) = 0x61 MIXED_EXT ALLOCATED  50_PCT_FULL                     DIFF (1:6) = CHANGED
35 ML (1:7) = NOT MIN_LOGGED            
36 
37 Slot 0 Offset 0x60 Length 31
38 
39 Record Type = PRIMARY_RECORD         Record Attributes =  NULL_BITMAP     
40 Memory Dump @0x0A01C060
41 
42 00000000:   10001c00 01000000 20202020 20202020 †........                 
43 00000010:   20202020 20202020 20202020 0200fc††††            ...          
44 
45 Slot 0 Column 0 Offset 0x4 Length 4
46 
47 id = 1                               
48 
49 Slot 0 Column 1 Offset 0x8 Length 20
50 
51 NAME =                               
52 
53 Slot 1 Offset 0x7f Length 31
54 
55 Record Type = PRIMARY_RECORD         Record Attributes =  NULL_BITMAP     
56 Memory Dump @0x0A01C07F
57 
58 00000000:   10001c00 02000000 c4e32020 20202020 †..........               
59 00000010:   20202020 20202020 20202020 0200fc††††            ...          
60 
61 Slot 1 Column 0 Offset 0x4 Length 4
62 
63 id = 2                               
64 
65 Slot 1 Column 1 Offset 0x8 Length 20
66 
67 NAME =68 
69 
70 DBCC 執行完畢。若是 DBCC 輸出了錯誤信息,請與系統管理員聯繫。
View Code
 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

指定char爲20,那麼就佔用20個字節的空間

 


總結

對於varchar數據類型,不管是空字符串仍是NULL值都不佔用任何空間

對於char數據類型,不管是空字符串仍是NULL值都佔用空間,所佔用空間大小取決於建表時候指定的char數據類型的大小

 

從上面的實驗來看,是否節省空間是根據數據類型來決定的而不是是不是NULL仍是空字符串

撇開數據類型來比較是沒有意義的,就像DATETIME數據類型的數據列填入NULL值和VARCHAR數據類型的數據列填入NULL值,

兩個NULL值進行比較,哪個大?若是不對兩種數據類型進行分析,單獨比較這兩個NULL值,這種比較是沒有意義的

並且也不平等,由於這兩種數據類型一點關係都沒有,一個datetime類型,一個是varchar類型

而char和varchar也是同樣

只有同一種數據類型的比較纔有意義,就像一樣都是varchar數據類型,空字符串和NULL值進行比較

一樣都是char數據類型,空字符串和NULL值進行比較

因此平時要對SQLSERVER中的數據類型要有必定認識,才能對系統中的表空間的使用狀況有大概的掌握

 

若有不對的地方,歡迎你們拍磚o(∩_∩)o

相關文章
相關標籤/搜索