1. 程式人生 > >翻譯:《Pro SQL Server Internals, 2nd edition》CHAPTER 1 Data Storage Internals中的Data Pages and Data Rows一節

翻譯:《Pro SQL Server Internals, 2nd edition》CHAPTER 1 Data Storage Internals中的Data Pages and Data Rows一節

觸發 nchar name 詳細 重建 server into evel 單位

原文鏈接:file:///E:/%E2%80%9C%E6%B2%BB%E6%9C%AA%E7%97%85%E2%80%9D%E5%81%A5%E5%BA%B7%E7%AE%A1%E7%90%86%E7%B3%BB%E7%BB%9F/Pro%20SQL%20Server%20Internals,%202nd%20edition.pdf

原著:《Pro SQL Server Internals》

作者:Dmitri Korotkevitch

翻譯:

數據頁面和數據行

數據庫中的空間分為邏輯8KB頁面。這些頁面從零開始連續編號,可以通過指定文件ID和頁碼來引用它們。頁面編號始終是連續的,這樣當SQL Server增加數據庫文件時,新頁面的編號從文件中的最高頁碼開始加一。同樣,當

SQL Server收縮文件時,它會刪除文件中的最高頁數。

技術分享圖片

一般來說,SQL Server中有三種不同的方式或技術存儲和使用數據庫中的數據。使用經典的基於行的存儲,數據存儲在數據行中將所有列的數據組合在一起。

SQL Server 2012引入了列存儲索引和基於列的存儲。這項技術存儲每列而不是每行的數據。我們將在這本書的第七部分中介紹基於列的存儲。

最後,SQL Server 2014中引入了一組內存技術並有了進一步改進。

SQL Server 2016中。即使它們將數據保留在磁盤上以達到減少冗余的目的,但它們的存儲格式與基於行和列的存儲非常不同。我們將在這本書第八部分中討論內存記憶的技術。

這一部分主要關註基於行的存儲和經典的

B-Tree索引和堆。

1-6顯示了數據頁面的結構。

技術分享圖片

1-6.數據頁面的結構

96字節頁眉包含有關頁面的各種信息,例如對象頁面所屬,頁面上可用的行數和可用空間量,鏈接到上一個如果頁面位於索引頁鏈中,則顯示下一頁,依此類推。

頁眉之後是存儲實際數據的區域。其次是自由空間。最後,有一個槽陣列,它是一個雙字節條目塊,表示相應數據的偏移量行開始在頁面上。

插槽陣列指示頁面上數據行的邏輯順序。如果頁面上的數據需要按照索引鍵的順序排序,SQL Server不對頁面上的數據行進行物理排序,而是它根據索引排序順序填充插槽數組。插槽0(圖1-6中最右側)存儲偏移量頁面上鍵值最小的數據行

;插槽1,第二低鍵值;等等。我們會在下一章中將更深入地討論索引。

SQL Server提供了一組豐富的系統數據類型,可以在邏輯上分為兩種不同的類型組:固定長度和可變長度。固定長度的數據類型,例如int,datetime,char等,即使它是NULL,也始終使用相同數量的存儲空間而不管它們的值。例如int列總是使用4個字節,nchar(10)列總是使用20個字節來存儲信息。

相比之下,可變長度數據類型(如varchar,varbinary和其他一些數據類型)使用同樣多存儲數據所需的存儲空間加上兩個額外的字節。例如,nvarchar(4000)列將僅使用12個字節來存儲五個字符的字符串,在大多數情況下,將使用兩個字節來存儲NULL值。我們將討論變長列不會在以後使用存儲空間用於NULL值的情況。

讓我們看一下數據行的結構,如圖1-7所示。

技術分享圖片

1-7.數據行的結構

該行的前兩個字節(稱為狀態位A和狀態位B)是包含信息的位圖關於行,如行類型,如果行已被邏輯刪除(幻影),以及行是否為NULL值,可變長度列和版本控制標記。

行中接下來的兩個字節用於存儲數據的固定長度部分的長度。他們後跟定長數據本身。

在固定長度數據部分之後,存在空位圖,其包括兩個不同的數據元素。第一個雙字節元素是行中的列數。第二個是空位圖數組。這個數組對表的每一列使用一位,無論它是否可為空。

空位圖始終存在於堆表或聚簇索引葉行中的數據行中,即使在表格沒有可空列。但是,空位圖不存在於非葉索引行中,也不存在於非葉索引行中索引中沒有可為空的列時,非聚簇索引的葉級行。

在空位圖之後,存在該行的可變長度數據部分。它以兩個字節開頭行中可變長度列的數量,後跟列偏移數組。 SQL Server存儲了兩個字節即使值為NULL,行中每個可變長度列的偏移值也是如此。接下來是數據的實際可變長度部分。最後,最後有一個可選的14字節版本控制標簽排。此標記在需要行版本控制的操作期間使用,例如聯機索引重建,樂觀的隔離級別,觸發器和其他一些。

■註意 我們將在第6章討論索引維護,第9章討論觸發器,以及在第21章討論樂觀隔離級別。

讓我們創建一個表,用一些數據填充它,然後查看實際的行數據。 代碼顯示在清單1-4。 復制功能重復作為第一個參數提供的字符十次。

清單1-4。 數據行格式:表創建

create table dbo.DataRows

(

ID int not null,

Col1 varchar(255) null,

Col2 varchar(255) null,

Col3 varchar(255) null

);

insert into dbo.DataRows(ID, Col1, Col3) values(1,replicate(‘a‘,10),replicate(‘c‘,10));

insert into dbo.DataRows(ID, Col2)

values (2,replicate(‘b‘,10));

dbcc ind (

‘SQLServerInternals‘ /*Database Name*/

,‘dbo.DataRows‘ /*Table Name*/

,-1 /*Display information for all pages of all indexes*/

);

未記錄但著名的DBCC IND命令返回有關表頁面的信息分配。在圖1-8中可以看到此命令的輸出。

技術分享圖片

1-8.DBCC IND輸出

有兩個屬於該表的頁面。第一個,PageType = 10,是一種特殊類型的頁面

稱為IAM分配圖。 此頁面跟蹤屬於特定對象的頁面。現在我們將在本章後面介紹分配地圖頁面。

註意SQL Server 2012引入了另一個未記錄的數據管理功能(DMF),sys.dm_db_

database_page_allocations,可用作DBCC IND命令的替代。 的輸出與DBCC IND相比,此DMF提供了更多信息,並且可以與其他系統DMV連接和/或目錄視圖。

PageType = 1的頁面是包含數據行的實際數據頁面。 PageFID和PagePID列顯示頁面的實際文件和頁碼。 您可以使用另一個未記錄的命令DBCC PAGE,檢查其內容,如清單1-5所示。

清單1-5。 數據行格式:DBCC PAGE調用

-- Redirecting DBCC PAGE output to console

dbcc traceon(3604);

dbcc page (

‘SqlServerInternals‘ /*Database Name*/

,1 /*File ID*/

,214643 /*Page ID*/

,3 /*Output mode: 3 - display page header and row details */

);

清單1-6顯示了與第一個數據行對應的DBCC PAGE的輸出。 SQL Server存儲字節交換順序的數據。 例如,兩字節值0001將存儲為0100。

清單1-6。 第一行的DBCC PAGE輸出

Slot 0 Offset 0x60 Length 39

Record Type = PRIMARY_RECORD

Record Attributes = NULL_BITMAP VARIABLE_COLUMNS

Record Size = 39

Memory Dump @0x000000000EABA060

0000000000000000: 30000800 01000000 04000403 001d001d 00270061 0................‘.a

0000000000000014: 61616161 61616161 61636363 63636363 636363 aaaaaaaaacccccccccc

Slot 0 Column 1 Offset 0x4 Length 4 Length (physical) 4 ID = 1

Slot 0 Column 2 Offset 0x13 Length 10 Length (physical) 10 Col1 = aaaaaaaaaa

Slot 0 Column 3 Offset 0x0 Length 0 Length (physical) 0 Col2 = [NULL]

Slot 0 Column 4 Offset 0x1d Length 10 Length (physical) 10 Col3 = cccccccccc

讓我們更詳細地看一下數據行,如圖1-9所示。

技術分享圖片

1-9:第一數據行

如圖所見,該行以兩個狀態位開始,後跟兩個字節的值0800。這是字節交換值0008,它是行中“列數”屬性的偏移量。這個偏移量告訴SQL Server行的固定長度數據部分結束。

接下來的四個字節用於存儲固定長度的數據,在我們的例子中是ID列。之後,有兩個字節的值表明數據行有四列,後跟一個字節的NULL位圖。只有四列,位圖中的一個字節就 足夠了。它存儲04的值,即00000100以二進制格式。它表示該行中的第三列包含NULL值。

接下來的兩個字節存儲行中可變長度列的數量,即3(以字節為單位的0300)訂購)。接下來是一個偏移數組,其中每兩個字節存儲可變長度的偏移量列數據結束。如您所見,即使Col2為NULL,它仍然使用偏移數組中的槽。最後,有來自可變長度列的實際數據。

現在,讓我們看看第二個數據行。清單1-7顯示了DBCC PAGE輸出,如圖1-10所示

行數據。

技術分享圖片

1-10:第二數據行

清單1-7。 第二行的DBCC PAGE輸出

Slot 1 Offset 0x87 Length 27

Record Type = PRIMARY_RECORD Record Attributes = NULL_BITMAP VARIABLE_COLUMNS

Record Size = 27

Memory Dump @0x000000000EABA087 0000000000000000: 30000800 02000000 04000a02 0011001b 00626262 0................bbb 0000000000000014: 62626262 626262 bbbbbbb

Slot 1 Column 1 Offset 0x4 Length 4 Length (physical) 4 ID = 2

Slot 1 Column 2 Offset 0x0 Length 0 Length (physical) 0 Col1 = [NULL]

Slot 1 Column 3 Offset 0x11 Length 10 Length (physical) 10 Col2 = bbbbbbbbbb

Slot 1 Column 4 Offset 0x0 Length 0 Length (physical) 0 Col3 = [NULL]

第二行中的NULL位圖表示二進制值00001010,其顯示Col1和Col3為NULL。 即使該表有三個可變長度列,可變長度的數量行中的列表示偏移數組中只有兩列/槽。 SQL Server沒有維護行中尾隨NULL可變長度列的信息。

第二行中的NULL位圖表示二進制值00001010,其顯示Col1和Col3為NULL。即使該表有三個可變長度列,可變長度的數量行中的列表示偏移數組中只有兩列/槽。 SQL Server沒有維護行中尾隨NULL可變長度列的信息。

■提示 你可以通過以可變長度的方式創建表來減小數據行的大小通常存儲空值的列被定義為CREATE TABLE語句中的最後一列。這是唯一一種CREATE TABLE語句中的列順序很重要的情況。

固定長度數據和內部屬性必須適合單個數據頁面上可用的8,060字節。如果不是這種情況,SQL Server不允許您創建表。例如,代碼清單1-8中的代碼產生錯誤。

清單1-8。創建一個數據行大小超過8,060字節的表

create table dbo.BadTable

(

Col1 char(4000),

Col2 char(4060)

)

Msg 1701, Level 16, State 1, Line 1

Creating or altering table ‘BadTable‘ failed because the minimum row size would be 8,067,

including 7 bytes of internal overhead. This exceeds the maximum allowable table row size of 8,060 bytes.

翻譯:《Pro SQL Server Internals, 2nd edition》CHAPTER 1 Data Storage Internals中的Data Pages and Data Rows一節