在SQL Server :理解數(shù)據(jù)頁結(jié)構(gòu)我們提到每條記錄都有7 bytes的系統(tǒng)行開銷,那這個7 bytes行開銷到底是一個什么樣的結(jié)構(gòu),我們一起來看下。
數(shù)據(jù)記錄存儲我們具體的數(shù)據(jù),換句話說,它存在堆表里,或者存在聚集索引的葉子節(jié)點。數(shù)據(jù)記錄結(jié)構(gòu)是為了讓SQL Server更高效的管理數(shù)據(jù)。我們來看下數(shù)據(jù)記錄結(jié)構(gòu)示意圖:
上圖中藍色部分是所有數(shù)據(jù)記錄部分(即系統(tǒng)行開銷,大小基于列個數(shù),等于或大于7 bytes),綠色部分是表結(jié)構(gòu)里取決于定長/變長列的數(shù)據(jù)記錄部分(實際存放的數(shù)據(jù),大小基于實際數(shù)據(jù))。
行頭系統(tǒng)數(shù)據(jù):用做狀態(tài)位1的第1字節(jié)(8位)是用來定義記錄的屬性:
用作狀態(tài)位2的第2字節(jié)(8位)。只有1位用來表示這條記錄是否為鬼影轉(zhuǎn)發(fā)記錄(ghost forwarded record)。
由行頭開始到定長列結(jié)尾長度:下2個字節(jié)用來存儲行頭開始到定長列結(jié)尾長度。它包含2個狀態(tài)位,2個字節(jié)用作這個列表示在表中定長數(shù)據(jù)的實際長度。例如如果表里沒有定長列,這個列的值會是4。這和頁頭列pminlen顯示的值是一樣的。
所有定長列字段值(Fixed_Data_Size):下n個字節(jié)用來存儲在表中的定長數(shù)據(jù),n就是在表中所有定長列的長度。如果表里的所有列都是變長列,這一部分就沒有。
空值位圖(Null_Bitmap):下2個字節(jié)用來存儲表里的列數(shù)。
下n個字節(jié)用作空值位圖,每個bit對應(yīng)一個列,1表示對應(yīng)列為空。n的值為:列數(shù) / 8,將值取整。
Variable_Data_Size:下2個字節(jié)用來存儲表里變長列個數(shù)。
下n個字節(jié)用來存儲每個變長列結(jié)束為止的偏移量。每個變長列需要2字節(jié),n的值為:變長列數(shù) * 2 。
最后n個字節(jié)用來存儲所有變長列值,n的值為所有變長列的實際長度的總長度。
我們來看一個具體的例子:
創(chuàng)建數(shù)據(jù)庫,并插入2條記錄
1 USE [InternalStorageFormat] 2 GO 3 4 IF EXISTS ( SELECT * 5 FROM sysobjects 6 WHERE id = OBJECT_ID(N'[dbo].[Customers]') 7 AND OBJECTPROPERTY(id, N'IsUserTable') = 1 ) 8 DROP TABLE dbo.Customers 9 10 CREATE TABLE Customers11 (12 FirstName CHAR(50) NOT NULL,13 LastName CHAR(50) NOT NULL,14 Address CHAR(100) NOT NULL,15 ZipCode CHAR(5) NOT NULL,16 Rating INT NOT NULL,17 ModifiedDate DATETIME NOT NULL,18 )19 GO20 21 22 INSERT INTO dbo.Customers23 ( FirstName ,24 LastName ,25 Address ,26 ZipCode ,27 Rating ,28 ModifiedDate29 )30 VALUES ( 'Woody' , -- FirstName - char(50)31 'Tu' , -- LastName - char(50)32 'ZUOQIAO YOUXI TOWN LINHAI CITY' , -- Address - char(50)33 '0000' , -- ZipCode - char(5)34 1 , -- Rating - int35 '2015-05-07 10:09:51' -- ModifiedDate - datetime36 )37 go 2
使用DBCC IND命令查看表對應(yīng)頁列表:
1 DBCC IND('InternalStorageFormat','Customers',-1)
我們看到數(shù)據(jù)頁號為79。
使用DBCC PAGE命令查看頁信息:
1 DBCC TRACEON(3604)2 DBCC PAGE(InternalStorageFormat,1,79,3)3 GO
在頁頭pminlen的值是221,包括定長列的總長217 bytes(50+50+100+5+4+8),2 bytes用作狀態(tài)位(行頭系統(tǒng)開銷),2 byte 用作由行頭開始到定長列結(jié)尾長度。
在記錄槽提到的長度224,包括頁頭pminlen的值,1 byte用作空值位圖(6/8 取整為1)和2 bytes 的字段個數(shù)。
我們來看一個變長列的表。
創(chuàng)建表并插入數(shù)據(jù)后,查看表對應(yīng)的頁:
1 CREATE TABLE VariableLength( 2 Title CHAR(10) NOT NULL, 3 FirstName VARCHAR(100), 4 Lastname VARCHAR(100), 5 email VARCHAR(50), 6 dob date NOT NULL, 7 phone CHAR(10), 8 Countrycode CHAR(3), 9 Designation VARCHAR(100),10 PersonalPreference VARCHAR(100)11 )12 GO13 INSERT INTO VariableLength VALUES ('Mr','Woody','Tu','smartgz@QQ.com','2015-5-7','XXXXXXXXXX','Chn','DBA','Nothing Spl')14 GO15 DBCC IND('InternalStorageFormat','VariableLength',-1)
我們看到數(shù)據(jù)頁號為202。
使用DBCC PAGE命令查看頁信息:
1 DBCC TRACEON(3604)2 GO3 DBCC PAGE('InternalStorageFormat',1,202,3)--記得根據(jù)你的實際數(shù)據(jù)庫,修改頁號202
pminlen值為30,包含:
Title CHAR(10) NOT NULL
dob date NOT NULL
phone CHAR(10)
Countrycode CHAR(3)
可以用下列語句驗證下定長列總長度:
1 SELECT DATALENGTH(Title) title,DATALENGTH(dob) dob,DATALENGTH(phone) phone,DATALENGTH(Countrycode) countrycode FROM VariableLength
在槽0顯示的81長度包含:
Title CHAR(10) NOT NULL
dob date NOT NULL
phone CHAR(10)
Countrycode CHAR(3)
FirstName VARCHAR(100)
Lastname VARCHAR(100)
email VARCHAR(50)
Designation VARCHAR(100)
PersonalPreference VARCHAR(100)
1 SELECT DATALENGTH(FirstName)+DATALENGTH(Lastname)+DATALENGTH(email)+2 DATALENGTH(Designation)+DATALENGTH(PersonalPreference) FROM VariableLength
總結(jié)下每條記錄的系統(tǒng)行開銷:
行頭系統(tǒng)數(shù)據(jù)(2 bytes)+由行頭開始到定長列結(jié)尾長度(2 bytes)+列個數(shù)(2 bytes)+空值位圖數(shù)據(jù)(取整(列個數(shù)/8) n bytes)
即 2 bytes + 2 bytes + 2 bytes + 取整(列個數(shù)/8)
當(dāng)列個數(shù)小于等于8時,系統(tǒng)行開銷始終是7 bytes,往上沒增加8列,增加1 bytes,即系統(tǒng)系統(tǒng)行開銷始終大于等于7 bytes。
對于在SQL Server里數(shù)據(jù)記錄的存儲格式,希望你已經(jīng)有了清晰的認識。
新聞熱點
疑難解答
圖片精選