2. 理解數據記錄結構

以下來自Woodytu的sqlserver存儲系列,一共八篇,記錄下來學習

https://www.cnblogs.com/woodytu/p/4486193.html

 

SQL Server 存儲(2/8):理解數據記錄結構

SQL Server :理解數據頁結構我們提到每條記錄都有至少7 bytes的系統行開銷,那這7 bytes行開銷到底是一個什麼樣的結構,我們一起來看下。

數據記錄存儲我們具體的數據,換句話說,它存在堆表裏,或者存在聚集索引的葉節點。數據記錄結構是爲了讓SQL Server更高效的管理數據。

我們來看下數據記錄結構示意圖:

https://images0.cnblogs.com/blog2015/750348/201505/072019401261661.png

上圖中藍色部分是所有數據記錄部分(即系統行開銷,大小基於列個數,等於或大於7 bytes),綠色部分是表結構裏取決於定長/變長列的數據記錄部分(實際存放的數據,大小基於實際數據)。

 

行頭系統數據

用作狀態位1的第1字節(8位)用來定義記錄的屬性

  • 第0位:版本信息,在SQL Server 2008裏始終是0;
  • 第1-3位:這3位用來定義記錄類型;
    • 0 數據記錄(data record)
    • 1 轉發記錄(Forwarded record)
    • 2 轉發存根(a forwarding stub)
    • 3 索引記錄(Index record)
    • 4 二進制堆碎片或行溢出數據(blob fragment or row overflow data)
    • 5 鬼影索引記錄(ghost index record)
    • 6 鬼影數據記錄(ghost data record)
    • 7 鬼影版本記錄(ghost version record)
  • 第4位:是否存在空值位圖(Null bitmap ),在SQL Server 2008裏沒有不爲空的列也會有空值位圖(Null bitmap );
  • 第5位:表示是否存在變長列;
  • 第6位:表示該列包含版本信息;
  • 第7位:在SQL Server裏未使用;

用作狀態位2的第2字節(8位)。只有1位用來表示這條記錄是否爲鬼影轉發記錄(ghost forwarded record)。

 

由行頭開始到定長列結尾長度(定長字段長度):

下2個字節用來表示從記錄開始到定長字段結束的總長度。即所有定長字段長度+4bytes系統數據(行頭2Bytes和定長字段長度記錄2Bytes)。例如如果表裏沒有定長列,這個列的值會是4。這和頁頭列pminlen顯示的值是一樣的。

 

所有定長列字段值(Fixed_Data_Size):

下n個字節用來存儲在表中的定長數據,n就是在表中所有定長列的長度。如果表裏的所有列都是變長列,這一部分就沒有。

字段個數:

下2個字節用來存儲表裏的列數

 

空值位圖(Null_Bitmap):

下n個字節用作空值位圖,每列對應一個bit,1表示對應列爲空。n的值爲:列數 / 8,取整。

 

Variable_Data_Size:

下2個字節用來存儲表裏變長列個數。

 

每個變長字段在記錄中的偏移量:

下n個字節用來存儲變長字段值在記錄中的實際偏移量。每個變長列需要2字節,n的值爲:變長列數 * 2 。

 

變長字段值:

最後n個字節用來存儲所有變長列值,n的值爲所有變長列的實際長度之和。

 

我們來看一個具體的例子:

創建測試表,並插入2條記錄

CREATE TABLE Customers

 (

    FirstName CHAR(50) NOT NULL,

    LastName CHAR(50) NOT NULL,

    Address CHAR(100) NOT NULL,

    ZipCode CHAR(5) NOT NULL,

    Rating INT NOT NULL,

    ModifiedDate DATETIME NOT NULL,

 )

 GO

 INSERT INTO dbo.Customers

         ( FirstName ,

           LastName ,

           Address ,

           ZipCode ,

           Rating ,

           ModifiedDate

         )

 VALUES  ( 'Woody' , -- FirstName - char(50)

           'Tu' , -- LastName - char(50)

           'ZUOQIAO YOUXI TOWN LINHAI CITY' , -- Address - char(50)

           '0000' , -- ZipCode - char(5)

           1 , -- Rating - int

           '2015-05-07 10:09:51'  -- ModifiedDate - datetime

         )

         go

使用DBCC IND命令查看錶對應頁列表:

 DBCC IND('InternalStorageFormat','Customers',-1)

https://images0.cnblogs.com/blog2015/750348/201505/072047199231384.png

我們看到數據頁號爲79

使用DBCC PAGE命令查看頁信息:

 DBCC TRACEON(3604)

 DBCC PAGE(InternalStorageFormat,1,79,3)

 GO 

https://images0.cnblogs.com/blog2015/750348/201505/072107185793521.png

在頁頭pminlen的值是221,包括定長列的總長217 bytes(50+50+100+5+4+8),2 bytes用作狀態位(行頭系統開銷),2 byte 用作由行頭開始到定長列結尾長度。

在記錄槽提到的長度224,包括頁頭pminlen的值,1 byte用作空值位圖(6/8 取整爲1)和2 bytes 的字段個數。

我們來看一個變長列的表。

創建表並插入數據後,查看錶對應的頁:

CREATE TABLE VariableLength(

    Title         CHAR(10) NOT NULL,

    FirstName     VARCHAR(100),

    Lastname      VARCHAR(100),

    email         VARCHAR(50),

    dob           date NOT NULL,

    phone         CHAR(10),

    Countrycode   CHAR(3),

    Designation   VARCHAR(100),

    PersonalPreference VARCHAR(100)

 )

 GO

 INSERT INTO VariableLength VALUES ('Mr','Woody','Tu','[email protected]','2015-5-7','XXXXXXXXXX','Chn','DBA','Nothing Spl')

 GO

 

 DBCC IND('InternalStorageFormat','VariableLength',-1)

https://images0.cnblogs.com/blog2015/750348/201505/072122176262724.png

我們看到數據頁號爲202。

使用DBCC PAGE命令查看頁信息:

 DBCC TRACEON(3604)

 GO

 DBCC PAGE('InternalStorageFormat',1,202,3)--記得根據你的實際數據庫,修改頁號202

https://images0.cnblogs.com/blog2015/750348/201505/072126478137479.png

pminlen值爲30,包含:

  • 1 byte 狀態位1
  • 1 byte 狀態爲2
  • 2 bytes 存儲行頭開始到定長列結尾長度
  • 26 bytes 所有定長列總長度(10+3+10+3:tittle,dob,phone,countrycode)
    • Title  CHAR(10) NOT NULL
    • dob date NOT NULL
    • phone CHAR(10)
    • Countrycode CHAR(3)

可以用下列語句驗證下定長列總長度: 

 SELECT DATALENGTH(Title) title,DATALENGTH(dob) dob,DATALENGTH(phone) phone,DATALENGTH(Countrycode) countrycode FROM VariableLength

 在槽0顯示的81長度包含:

  • 1 byte 狀態位1
  • 1 byte 狀態爲2
  • 2 bytes 存儲行頭開始到定長列結尾長度
  • 26 bytes 所有定長列總長度(10+3+10+3:tittle,dob,phone,countrycode)
    • Title  CHAR(10) NOT NULL
    • dob date NOT NULL
    • phone CHAR(10)  
    • Countrycode CHAR(3)
  • 2 bytes 存儲列個數
  • 2 bytes 用作空值位圖,字段個數/8後取整,即 9/8 得到2
  • 2 bytes 存儲變長列個數
  • 10 bytes 用來存儲每個變長列結束位置的偏移量 變長列個數 * 2,即 5 * 2 得到10,5個變長列包含:
    • FirstName VARCHAR(100)
    • Lastname VARCHAR(100)  
    • email VARCHAR(50)
    • Designation VARCHAR(100)  
    • PersonalPreference VARCHAR(100)
  • 35 bytes 用來存儲所有變長列的實際長度,這個可以使用下列語句得到

 SELECT DATALENGTH(FirstName)+DATALENGTH(Lastname)+DATALENGTH(email)+

 DATALENGTH(Designation)+DATALENGTH(PersonalPreference) FROM VariableLength

https://images0.cnblogs.com/blog2015/750348/201505/072144302824789.png

總結下每條記錄的系統行開銷:

行頭系統數據(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裏數據記錄的存儲格式,希望你已經有了清晰的認識。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章