星尘小组第八周翻译-数据页和数据行
數據頁和數據行
數據庫中的空間被劃分為8KB的邏輯頁面。這些頁面從0開始連續編號,可以通過指定文件ID和頁碼引用它們。頁面編號始終是連續的,因此當SQL Server增長數據庫文件時,新頁面的編號從文件中最大的頁碼加1開始。類似地,當SQL Server刪減文件時,它會從文件中刪除數量最多的頁面。
SQL SERVER中的數據存儲
一般來說,SQL Server有三種不同的方法或技術來存儲和處理數據庫中的數據。使用傳統的基于行的存儲,數據存儲在將所有數據結合在一起的數據行中。
SQL Server 2012引入了列存儲索引和基于列的存儲。該技術按每列而不是按行存儲數據。我們將在本書的第七部分介紹基于列的存儲。
最后,在SQL Server 2014中引入了一組內存技術,并在SQL Server 2016中進行了進一步的改進。盡管它們將數據保存在磁盤上存在冗余的問題,但是它們的存儲格式與基于行和列的存儲都非常不同。我們將在本書第八部分討論內存技術。
本書的這一部分主要介紹基于行的存儲和經典的多路搜索樹的索引和堆。
圖片 1-6顯示了數據頁的結構。
圖片1-6 數據頁結構
一個96字節的頁眉包含關于頁面的各種信息,例如頁面所屬的對象、頁面上可用的行數和空閑空間量,如果頁面位于索引頁面鏈中,則指向上一頁和下一頁的鏈接,等等。
頁眉后面是存儲實際數據的區域。然后是自由空間。最后有一個插槽數組,它是一個兩字節的條目塊,指示相應數據行在頁面上開始的偏移量。
插槽數組指示頁面上數據行的邏輯順序。如果需要按照索引鍵的順序對頁面上的數據進行排序,SQL Server不會對頁面上的數據行進行物理排序,而是根據索引排序順序填充插槽數組。Slot 0(圖1-6中最右邊)存儲頁面上鍵值最低的數據行的偏移量; Slot 1,鍵值第二低;等等。我們將在下一章更深入地討論索引。
SQL Server提供了一組豐富的系統數據類型,這些數據類型可以邏輯地分為兩組:固定長度和可變長度。固定長度的數據類型,如int、datetime、char和其他類型,無論它們的值是什么,總是使用相同數量的存儲空間,即使它是空的也是如此。例如,int列總是使用4個字節,nchar(10)列總是使用20個字節來存儲信息。
相反,可變長度的數據類型,如varchar、varbinary和其他一些類型,使用的存儲空間與存儲數據所需的存儲空間一樣多,另外還有兩個額外的字節。例如,nvarchar(4000)列只使用12個字節來存儲一個5個字符的字符串,在大多數情況下,使用2個字節來存儲一個空值。本章稍后我們將討論變長列不為空值使用存儲空間的情況。
讓我們看看數據行的結構,如圖1-7所示。
?
?
行的前兩個字節稱為狀態位A和狀態位B,它們是位圖,包含關于行的信息,比如行類型,如果行已經邏輯刪除(重影),如果行有空值、可變長度列和版本控制標記。
行中接下來的兩個字節用于存儲數據中固定長度部分的長度。然后是固定長度的數據本身。
在固定長度的數據部分之后,有一個空位圖,它包含兩個不同的數據元素。第一個雙字節元素是行中的列數。第二個是一個空位圖數組。這個數組對表的每一列使用一個位,不管它是否為空。
空位圖總是出現在堆表或聚集索引葉行的數據行中,即使表中沒有可空列。然而,當索引中沒有可空列時,空位圖既不存在于非葉索引行中,也不存在于非聚集索引的葉級行中。
在空位圖之后,有一行的可變長度數據部分。它以行中可變長度列的雙字節數開始,然后是列偏移數組。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_allocation,可以用作DBCC IND命令的替換。與DBCC IND相比,這個DMF的輸出提供了更多的信息,并且可以與其他系統dmv和/或目錄視圖連接。
PageType=1的頁面是包含數據行的實際數據頁面。PageFID和PagePID列顯示頁面的實際文件和頁碼。您可以使用另一個未文檔化的命令DBCC PAGE來檢查它的內容,如清單1-5所示。
清單1 - 5。數據行格式:DBCC頁面調用
-- 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頁面的輸出。SQL Server以字節交換的順序存儲數據。例如,兩個字節的值0001將存儲為0100。
清單1 - 6。第一行的DBCC頁面輸出
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行中固定長度的數據部分在哪里結束。
接下來的4個字節用于存儲固定長度的數據,在我們的示例中是ID列。然后是兩個字節的值,該值顯示數據行有四列,然后是一個一個字節的空位圖。如果只有四列,位圖中的一個字節就足夠了。它以二進制格式存儲04的值,即00000100。它表示行中的第三列包含空值。
接下來的兩個字節存儲行中可變長度列的數量,即3(字節順序為0300)。它后面是一個偏移量數組,其中每兩個字節存儲變量列數據結束的偏移量。如您所見,即使Col2為NULL,它仍然使用偏移數組中的插槽。最后,還有來自可變長度列的實際數據。
現在,讓我們看看第二個數據行。
下列清單顯示DBCC頁面輸出,圖1-10顯示行數據。
DBCC頁輸出第二行:
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 lot 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]圖1 - 10.第二數據行數據
?
第二行中的NULL位圖表示二進制值00001010,表示Col1和Col3是NULL。
即使表有三個可變長列,行中可變長列的數量表明偏移數組中只有兩列/槽。SQL Server不維護行中尾隨的空變長列的信息。
?
【提示】您可以在創建表時減少數據行的大小,方法是將通常存儲null值的變長列定義為CREATE TABLE語句中的最后一列。這是CREATE TABLE語句聲明事項中的按順序排列的唯一一列。
?
固定長度的數據和內部屬性必須適合單個數據頁上可用的8060個字節。如果不是這樣,SQL Server將不允許您創建表。例如,如下代碼產生了一個錯誤。
?
創建數據行大小超過8060字節的表:
?
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.?
轉載于:https://www.cnblogs.com/hawking-520/p/10730010.html
總結
以上是生活随笔為你收集整理的星尘小组第八周翻译-数据页和数据行的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 理解并发进程
- 下一篇: Python基础之二进制