在SQL Server :理解數據頁結構我們提到每條記錄都有7 bytes的系統行開銷,那這個7 bytes行開銷到底是一個什么樣的結構,我們一起來看下。
數據記錄存儲我們具體的數據,換句話說,它存在堆表里,或者存在聚集索引的葉子節點。數據記錄結構是為了讓SQL Server更高效的管理數據。我們來看下數據記錄結構示意圖:
上圖中藍色部分是所有數據記錄部分(即系統行開銷,大小基于列個數,等于或大于7 bytes),綠色部分是表結構里取決于定長/變長列的數據記錄部分(實際存放的數據,大小基于實際數據)。
行頭系統數據:用做狀態位1的第1字節(8位)是用來定義記錄的屬性:
用作狀態位2的第2字節(8位)。只有1位用來表示這條記錄是否為鬼影轉發記錄(ghost forwarded record)。
由行頭開始到定長列結尾長度:下2個字節用來存儲行頭開始到定長列結尾長度。它包含2個狀態位,2個字節用作這個列表示在表中定長數據的實際長度。例如如果表里沒有定長列,這個列的值會是4。這和頁頭列pminlen顯示的值是一樣的。
所有定長列字段值(Fixed_Data_Size):下n個字節用來存儲在表中的定長數據,n就是在表中所有定長列的長度。如果表里的所有列都是變長列,這一部分就沒有。
空值位圖(Null_Bitmap):下2個字節用來存儲表里的列數。
下n個字節用作空值位圖,每個bit對應一個列,1表示對應列為空。n的值為:列數 / 8,將值取整。
Variable_Data_Size:下2個字節用來存儲表里變長列個數。
下n個字節用來存儲每個變長列結束為止的偏移量。每個變長列需要2字節,n的值為:變長列數 * 2 。
最后n個字節用來存儲所有變長列值,n的值為所有變長列的實際長度的總長度。
我們來看一個具體的例子:
創建數據庫,并插入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命令查看表對應頁列表:
1 DBCC IND('InternalStorageFormat','Customers',-1)
我們看到數據頁號為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用作狀態位(行頭系統開銷),2 byte 用作由行頭開始到定長列結尾長度。
在記錄槽提到的長度224,包括頁頭pminlen的值,1 byte用作空值位圖(6/8 取整為1)和2 bytes 的字段個數。
我們來看一個變長列的表。
創建表并插入數據后,查看表對應的頁:
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)
我們看到數據頁號為202。
使用DBCC PAGE命令查看頁信息:
1 DBCC TRACEON(3604)2 GO3 DBCC PAGE('InternalStorageFormat',1,202,3)--記得根據你的實際數據庫,修改頁號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
總結下每條記錄的系統行開銷:
行頭系統數據(2 bytes)+由行頭開始到定長列結尾長度(2 bytes)+列個數(2 bytes)+空值位圖數據(取整(列個數/8) n bytes)
即 2 bytes + 2 bytes + 2 bytes + 取整(列個數/8)
當列個數小于等于8時,系統行開銷始終是7 bytes,往上沒增加8列,增加1 bytes,即系統系統行開銷始終大于等于7 bytes。
對于在SQL Server里數據記錄的存儲格式,希望你已經有了清晰的認識。
新聞熱點
疑難解答