1. 程式人生 > >《Pro SQL Server Internals》之Data Pages Data Rows

《Pro SQL Server Internals》之Data Pages Data Rows

本文選自《Pro SQL Server Internals》

作者: Dmitri Korotkevitch

出版社: Apress

出版年: 2016-12-29

頁數: 804

作者簡介:Dmitri Korotkevitchis是微軟SQL Server MVP和微軟認證大師。作為應用程式和資料庫開發人員、資料庫管理員和資料庫架構師,他具有多年使用SQL Server的經驗。他專門從事OLTP系統在高負載下的設計、開發和效能調優。Dmitri經常在各種Microsoft和SQL PASS活動上發言,他為世界各地的客戶提供SQL Server培訓。

原文連結:http://www.doc88.com/p-4042504089228.html

章節一:資料儲存內部

 

圖1-5.檢查是否使用了初始化檔案的sql伺服器錯誤日誌

Another important database option that controls database file sizes is Auto Shrink . When this option is enabled, SQL Server shrinks the database files every 30 minutes, reducing their size and releasing the space to the operating system. This operation is very resource intensive and is rarely useful, as the database files grow again when new data comes into the system. Moreover, it greatly increases index fragmentation in the database. Auto Shrink should never be enabled. Moreover, Microsoft will remove this option in future versions of SQL Server.

另一個控制資料庫檔案大小的重要資料庫選項是自動收縮。當此選項為啟用,SQL伺服器每30分鐘就縮小資料庫檔案,在作業系統中,減少其所佔記憶體並釋放空間。這個操作非常耗費資源而且很少有用,因為在資料庫檔案中,當新資料進入系統時,會再增長一次。此外,在資料庫中,它還極大地增加了索引碎片。不應該啟用自動收縮。此外,在未來的sql伺服器版本中,微軟今後將移除這一這個選項。

 Note We will talk about index fragmentation in greater detail in Chapter 6 , “Index Fragmentation.”

注意,我們將在第六章“索引碎片”中更詳細地討論索引碎片。

Data Pages and Data Rows

資料頁和資料行

  The space in the database is divided into logical 8KB pages . These pages are continuously numbered starting with zero, and they can be referenced by specifying a file ID and page number. The page numbering is always continuous, such that when SQL Server grows the database file,

new pages are numbered starting from the highest page number in the file plus one. Similarly, when SQL Server shrinks the file, it removes the highest-number pages from the file.

   資料庫中的空間分為邏輯8KB頁。這些頁面從零開始連續編號,可以通過指定檔案ID和頁碼來引用。頁面編號是連續的,所以當SQL伺服器生成資料庫檔案時,新頁面的編號從檔案中的最高頁碼加1開始。類似地,當SQL伺服器縮小檔案時,它會刪除檔案中最高的頁。

DATA STORAGE IN SQL SERVER

在sql伺服器中儲存資料

Generally speaking, there are three different ways, or technologies, in which SQL Server stores and works with the data in the database. With the classic row-based storage , the data is stored in data rows that combine the data from all columns together.

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

SQL Server 2012 introduced columnstore indexes and column-based storage . This technology stores the data on a per-column rather than a per-row basis. We will cover column-based storage in Part VII of this book.

SQL Server 2012推出了柱狀儲存索引和基於柱狀儲存。此技術將資料儲存在每列而不是每行。我們會在第7部分介紹柱式儲存這部分。

Finally, there is the set of in-memory technologies introduced in SQL Server 2014 and further improved in SQL Server 2016. Even though they persist the data on disk for redundancy purposes, their storage format is very different from both row- and column-based storage. We will discuss in-memory technologies in Part VIII of this book.

最後,在SQL Server 2014中引入了一套記憶體技術,並在2016年SQL Server中進一步改進。即使他們堅持將資料儲存在磁碟上是為了減少冗餘,但是他們的儲存格式與基於行和列的儲存有很大的不同。我們將在本書第八部分討論記憶體技術。

 This part of the book is focused on row-based storage and classic B-Tree indexes and heaps.

這部分書的重點是基於行的儲存和經典的b樹索引和堆。

Figure  1-6 shows the structure of a data page.

圖1-6顯示了資料頁的結構

 

Figure 1-6. The data page structure  

圖1-6.資料頁結構

A 96-byte page header contains various pieces of information about a page, such as the object to which the page belongs, the number of rows and amount of free space available on the page, links to the previous and next pages if the page is in an index-page chain, and so on.

一個96位元組的頁首包含了關於頁面的各種資訊片段,例如頁面所屬的物件、頁面上可用的行數和可用空間的數量,如果頁面在索引頁鏈中,則可連結到上一頁和下一頁等等。

 Following the page header is the area where actual data is stored. This is followed by free space. Finally, there is a slot array, which is a block of two-byte entries indicating the offset at which the corresponding data rows begin on the page.

頁首之後是實際資料的儲存區域。接下來是自由空間。最後,還有一個空閒陣列,它是一個由兩個位元組組成的空閒框,表示在頁面上相應資料行開始時的偏移量。

 The slot array indicates the logical order of the data rows on the page. If data on a page needs to be sorted in the order of the index key, SQL Server does not physically sort the data rows on the page, but rather it populates the slot array based on the index sort order. Slot 0 (rightmost in Figure  1-6 ) stores the offset for the data row with the lowest key value on the page; slot 1, the second-lowest key value; and so forth. We will discuss indexes in greater depth in the next chapter.

空閒陣列的指示是頁上資料行的邏輯順序。如果頁面上的資料需要按照索引鍵的順序排序,SQL Server不會對頁面上的資料行進行物理排序,而是根據索引順序填充空閒陣列。空閒框0(圖1-6中最右邊)儲存頁面上鍵值最低的資料行的偏移量;空閒框1,鍵值次低的資料行的偏移量等等。我們將在下一章更深入地討論索引。

 SQL Server offers a rich set of system data types that can be logically separated into two different groups: fixed length and variable length. Fixed-length data types, such as int , datetime , char , and others, always use the same amount of storage space regardless of their value, even when it is NULL . For example, the int column always uses 4 bytes and an nchar(10) column always uses 20 bytes to store information.

SQL Server提供了一組豐富的系統資料型別,這些資料型別在邏輯上可以分為兩個不同的組:固定長度和可變長度。固定長度的資料型別,如int、日期時間、char等,無論其值如何,總是使用相同數量的儲存空間,即使它是空的。例如,int型別總是使用4位元組,nchar(10)型別總是使用20位元組來儲存資訊。

 In contrast, variable-length data types, such as varchar , varbinary , and a few others, use as much storage space as is required to store data, plus two extra bytes. For example, an nvarchar(4000) column would use only 12 bytes to store a five-character string and, in most cases, two bytes to store a NULL value. We will discuss the case where variable-length columns do not use storage space for NULL values later in this chapter.

相比之下,可變長度的資料型別,如varchar、varbinary和其他的型別,使用儲存資料所需的儲存空間,需要再加上兩個額外的位元組。例如,nvarchar(4000)型別只使用12個位元組來儲存一個五個字元的字串,在大多數情況下,使用兩個位元組來儲存一個空值。我們將在本章後面討論可變長列不使用空值儲存空間的情況。

 Let’s look at the structure of a data row, as shown in Figure  1-7 .

讓我們看看資料行的結構,如圖1-7所示。

 

The first two bytes of the row, called Status Bits A and Status Bits B , are bitmaps that contain information about the row, such as row type, if the row has been logically deleted (ghosted), and if the row has NULL values, variable-length columns, and a versioning tag.

行的前兩個位元組,稱為狀態位A和狀態位B,是點陣圖,其中包含關於行的資訊,比如行型別,如果行已經被邏輯刪除(重定向),如果行有空值、可變長度列和版本控制標記。

The next two bytes in the row are used to store the length of the fixed-length portion of the data. They are followed by the fixed-length data itself.

行中接下來的兩個位元組用於儲存資料的固定長度部分的長度。然後是固定長度的資料本身。

 After the fixed-length data portion, there is a null bitmap , which includes two different data elements. The first two-byte element is the number of columns in the row. The second is a null bitmap array. This array uses one bit for each column of the table, regardless of whether it is nullable or not.

在固定長度的資料部分之後,有一個空點陣圖,它包含兩個不同的資料元素。第一個雙位元組元素是行中的列數。第二個是空點陣圖陣列。這個陣列對錶的每一列使用一位,不管它是否為空。

A null bitmap is always present in data rows in heap tables or clustered index leaf rows, even when the table does not have nullable columns. However, the null bitmap is not present in non-leaf index rows nor in leaf-level rows of nonclustered indexes when there are no nullable columns in the index.

空點陣圖總是出現在堆表或聚集索引葉行的資料行中,即使表沒有可空列。但是,當索引中沒有可空列時,空點陣圖不會出現在非葉索引行中,也不會出現在非聚集索引的葉級行中。

 Following the null bitmap, there is the variable-length data portion of the row. It starts with a two-byte number of variable-length columns in the row followed by a column-offset array.  SQL Server stores a two-byte offset value for each variable-length column in the row, even when the value is NULL. It is followed by the actual variable-length portion of the data.  Finally, there is an optional 14-byte versioning tag at the end of the row. This tag is used during operations that require row versioning,such as an online index rebuild, optimistic isolation levels, triggers, and a few others.

在空點陣圖之後,存在該行的可變長度資料部分。它以行中兩個位元組數量的可變長度列開始,接著是列-偏移陣列。SQL 伺服器為行中的每個可變長列儲存一個雙位元組偏移量值,即使該值為空。然後是資料的實際可變長度部分。最後,在該行的末尾有一個可選的14位元組版本標記。此標記用於需要行版本控制的操作,例如線上索引重建、樂觀隔離級別、觸發器和其他一些操作。

Let’s create a table, populate it with some data, and look at the actual row data. The code is shown in Listing 1-4 . The Replicate function repeats the character provided as the first parameter ten times.

讓我們建立一個表,用一些資料填充它,並檢視實際的行資料。程式碼如列表1-4所示。複製函式將第一個引數提供的字元重複10次。

 Listing 1-4. The data row format: Table creation

列表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*/

);

 An undocumented but well-known DBCC IND command returns information about table page allocations. You can see the output of this command in Figure  1-8 .

一個無記錄的但知名的DBCC IND命令返回了關於頁面分配的資訊。您可以在圖1-8中看到該命令的輸出。

 

Figure 1-8. DBCC IND output

圖1-8 DBCC IND 輸出

 There are two pages that belong to the table. The first one, with PageType=10 , is a special type of page called an IAM allocation map . This page tracks the pages that belong to a particular object.Do not focus on that now, however, as we will cover allocation map pages later in this chapter.

有兩個頁面是屬於這個表的。第一個,帶有PageType = 10,是被稱為IAM分配對映的特殊型別的頁面。這一頁記錄了某個特定物件的頁面。但是,現在不要專注於此,因為我們將在本章後面討論分配對映頁面。

Note SQL Server 2012 introduces another undocumented data-management function (DMF) , sys.dm_db_database_page_allocations , which can be used as a replacement for the DBCC IND command. The output of this DMF provides more information when compared to DBCC IND , and it can be joined with other system DMVs and/or catalog views.

筆記 SQL Server 2012引入了另一個未文件化的資料管理功能(DMF) sys。dm_db_database_page_assignments,它可以用作DBCC IND命令的替代。與DBCC IND相比,此DMF的輸出提供了更多資訊,並且可以與其他系統dmv和/或目錄檢視連線。

 The page with PageType=1 is the actual data page that contains the data rows. The PageFID and PagePID columns show the actual file and page numbers for the page. You can use another undocumented command, DBCC PAGE , to examine its contents, as shown in Listing 1-5.

帶有PageType = 1的頁面是包含資料行的實際資料頁面。PageFID和PagePID列顯示了頁面的實際檔案和頁碼。您可以使用另一個未文件化的命令DBCC PAGE來檢查其內容,如列表1-5所示。

 Listing 1-5. The data row format: DBCC PAGE call

列表1-5 資料行格式:DBCC頁面呼叫

-- Redirecting DBCC PAGE output to console

——頁面重定向DBCC輸出到控制檯

dbcc traceon(3604);

dbcc page

(

 'SqlServerInternals' /*Database Name*/

 ,1 /*File ID*/

 ,214643 /*Page ID*/

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

);

 Listing 1-6 shows the output of the DBCC PAGE that corresponds to the first data row. SQL Server stores the data in byte-swapped order. For example, a two-byte value of 0001 would be stored as 0100 .

列表1-6顯示了對應於第一行資料的DBCC頁面的輸出。SQL Server以位元組交換的順序儲存資料。例如,兩個位元組的值0001將儲存為0100。

 

Listing 1-6. DBCC PAGE output for the first row 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

 Let’s look at the data row in more detail, as shown in Figure  1-9 .

讓我們更詳細地檢視資料行,如圖1-9所示。

 

Figure 1-9. First data row

 As you can see, the row starts with the two status bits followed by a two-byte value of 0800 . This is the byte-swapped value of 0008 , which is the offset for the Number of Columns attribute in the row. This offset tells SQL Server where the fixed-length data part of the row ends.

正如您所看到的,行以兩個狀態位開始,然後是兩個位元組的值0800。這是位元組交換值0008,它是行中列數屬性的偏移量。這個偏移量告訴SQL Server行中固定長度的資料部分在哪裡結束。

 The next four bytes are used to store fixed-length data, which is the ID column in our case. After that, there is the two-byte value that shows that the data row has four columns, followed by a one-byte NULL bitmap. With just four columns, one byte in the bitmap is enough. It stores the value of 04 , which is 00000100in the binary format. It indicates that the third column in the row contains a NULL value.

接下來的4個位元組用於儲存固定長度的資料,在我們的示例中是ID列。在那之後,有一個雙位元組值顯示資料行有四列,然後是一個單位元組的空點陣圖。如果只有四列,點陣圖中的一個位元組就足夠了。它以二進位制格式儲存04的值,即00000100。它表示行中的第三列包含空值。

   The next two bytes store the number of variable-length columns in the row, which is 3 ( 0300 in byte[1]swapped order). It is followed by an offset array, in which every two bytes store the offset where the variable[1]length column data ends. As you can see, even though Col2 is NULL, it still uses the slot in the offset array. Finally, there is the actual data from the variable-length columns.

  接下來的兩個位元組儲存行中可變長度列的數量,即3(位元組順序為0300)。它後面是一個偏移量陣列,其中每兩個位元組儲存變數列資料結束的偏移量。如您所見,即使Col2為NULL,它仍然使用偏移陣列中的插槽。最後,還有來自可變長度列的實際資料。

   Now, let’s look at the second data row. Listing 1-7 shows the DBCC PAGE output, and Figure  1-10 shows

the row data.

現在,讓我們看看第二個資料行。清單1-7顯示DBCC頁面輸出,圖1-10顯示行資料。

Figure 1-10.    Second data row data      

圖1-10。第二資料行資料

Listing 1-7.    DBCC PAGE output for the second  row     

清單1-7。第二行的DCBC頁輸出

 

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]  

 

The NULL bitmap in the second row represents a binary value of 00001010 , which shows that  Col1 and Col3 are NULL. Even though the table has three variable-length columns, the number of variable-length columns in the row indicates that there are just two columns/slots in the offset array. SQL Server does not maintain the information about the trailing NULL variable-length columns in the row.

第二行中的NULL位圖表示二進位制值00001010,表明Col1和Col3是NULL。即使表有三個可變長度列,行中可變長度列的數量表明偏移陣列中只有兩個列/插槽。SQL Server不維護關於行中尾隨的NULL可變長度列的資訊。

 

Tip  You can reduce the size of the data row by creating tables in a manner in which variable-length columns, which usually store null values, are defined as the last ones in the  CREATE TABLE statement. This is the only case in which the order of columns in the CREATE TABLE  statement matters. 

提示:通過建立表,可以將通常儲存空值的可變長列定義為CREATE TABLE語句中的最後一個列,可以減少資料行的大小。這是CREATE TABLE語句中列順序唯一重要的情況。

 

The fixed-length data and internal attributes must fit into the 8,060 bytes available on the single data page. SQL Server does not let you create the table when this is not the case. For example, the code in Listing  1-8  produces an error.

固定長度的資料和內部屬性必須符合單個數據頁上可用的8060位元組。當情況不是這樣時,SQLServer不允許您建立表。例如,清單1-8中的程式碼會產生錯誤。

CHAPTER 1  DATA STORAGE INTERNALS

第一章 資料儲存內部構件

 

Listing 1-8.  Creating a table with a data row size that exceeds 8,060  bytes    

列表1-8. 建立一個表,它的資料行大小超過8060

 

 create table dbo.BadTable //建立一個表,表名為dbo.BadTable

 (

     Col1 char(4000), //定義一個長度為4000的資料Col1

     Col2 char(4060) //定義一個長度為4060的資料Col2

 )

 

Large  Objects Storage 

Even though the fixed-length data and the internal attributes of a row must fit into a single page, SQL Server can store the variable-length data on different data pages. There are two different ways to store the data, depending on the data type and length.

Msg 1701,16級,狀態1,第1行

建立或更改“BadTable”表失敗,因為最小行的大小是8067,包括7個位元組的內部開銷。這超過了最大表行允許的8060位元組。

 

SQL Server stores variable-length column data that does not exceed 8,000 bytes on special pages called row-overflow pages.  Let’s create a table and populate it with the data shown in Listing  1-9 . 

大物件儲存

即使固定長度資料和行的內部屬性必須適合於單個頁面,SQL Server也可以將可變長度資料儲存在不同的資料頁上。根據資料型別和長度,有兩種不同的方法儲存資料。

 

Row-Overflow Storage

SQL Server stores variable-length column data that does not exceed 8,000 bytes on special pages called row-overflow pages.  Let’s create a table and populate it with the data shown in Listing  1-9 .

溢位儲存

QL Server在稱為行溢位頁的特殊頁上儲存不超過8000位元組的可變長度列資料。讓我們建立一個表並用清單1-9所示的資料填充它。

 

Listing 1-9.  Row-overflow data: Creating a table  

清單1-9。行溢位資料:建立表

 

 create table dbo.RowOverflow  //建表,表名為dbo.RowOverflow

 (

     ID int not null,  //定義一個整型資料,資料名為ID,不允許為空

     Col1 varchar(8000) null, //定義一個變長資料,資料名為Col1,長度為8000,允許為空

     Col2 varchar(8000) null  //定義一個變長資料,資料名為Col2,長度為8000,允許為空

 );

insert into dbo.RowOverflow(ID, Col1, Col2) values (1,replicate('a',8000),replicate('b',8000)); //插入一行記錄,“ID”的值為1,“Col1”的值為a,a等於8000,“Col2”的值為b,b等於8000

As you see, SQL Server creates the table and inserts the data row without any errors, even though the data-row size exceeds 8,060 bytes. Let’s look at the table page allocation using the  DBCC IND  command. The results are shown in Figure  1-11 . 

正如你所見,SQL Server建立表並插入資料行,即使資料行大小超過8060位元組,也沒有任何錯誤。讓我們看看使用DCBC IND的命令分配表頁。結果如圖1-11所示。

 

Figure 1-11.  R  ow-overflow data: DBCC IND results       

圖1-11。溢位資料:DCBC IND結果