SQL Server 深刻解析索引存儲(彙集索引)

標籤:SQL SERVER/MSSQL SERVER/數據庫/DBA/索引體系結構/堆/彙集索引數據庫

概述

最近要分享一個課件就從新把這塊知識整理了一遍出來,篇幅有點長,想要理解的透徹仍是要上機實踐。測試

 

 

 

彙集索引

--建立測試數據庫
CREATE DATABASE Ixdata
GO
USE [Ixdata]
GO
---建立測試表
CREATE TABLE Orders
(ID INT PRIMARY KEY IDENTITY(1,1),
NAME CHAR(80)NOT NULL,
IDATE DATETIME NOT NULL DEFAULT(GETDATE())
);
GO
---插入1000條測試數據
DECLARE @ID INT=1
WHILE(@ID<=1000)
BEGIN
INSERT INTO Orders(NAME)VALUES('商品'+CONVERT(NVARCHAR(20),@ID))
SET @ID=@ID+1 
END
GO
SELECT * FROM Orders 
GO

分析新建立的表的頁的信息編碼

---顯示跟蹤標誌的狀態
DBCC TRACESTATUS

---開啓跟蹤標誌
DBCC TRACEON(3604,2588)
--DBCC TRACEOFF(3604,2588)
---獲取對象的數據頁,結構:數據庫、對象、顯示
DBCC IND(Ixdata,Orders,-1)

/*
1:顯示全部分頁的信息,包括IAM分頁,數據分頁,全部存在的LOB分頁和行溢出頁,索引分頁
-1: 顯示全部IAM、數據分頁、及指定對象上所有索引的索引分頁.
-2: 顯示指定對象的全部IAM分頁
0:顯示全部IAM、數據分頁.
*/spa

DBCC IND的表結構

還能夠經過另外一種方法來測試:3d

SELECT DISTINCT so.name, so.object_id,i.name AS index_name,sp.index_id,internals.type_desc,internals.total_pages, internals.used_pages, internals.data_pages,first_iam_page,  first_page, root_page
FROM sys.objects so
INNER JOIN sys.partitions sp ON so.object_id = sp.object_id
INNER JOIN sys.allocation_units sa ON sa.container_id = sp.hobt_id
INNER JOIN sys.system_internals_allocation_units internals ON internals.container_id = sa.container_id
LEFT JOIN sys.indexes  i ON so.object_id=i.object_id AND sp.index_id=i.index_id
WHERE so.object_id = object_id('orders') 

 最後三個字段分別是IAM頁,根頁,和第一個數據頁;它們分別用16進制來表示,拿first_iam_page來分析,首先將編碼從右往左一個字節接着一個字節反過來排行(0X表明16進制),結果就是0X,00 01,00 00 00 50;前兩個字節表明文件組號,最後4個字節表明頁號。16進制的0001轉換成10進制就是1;16進制的00 00 00 50轉換成10進制就是5*16的1次方=5*16=80,因此第一個數據頁是4*16+15=79,根頁是5*16+9=89 結果和前面的查詢出來的結果是同樣的。從表格的otal_pages,used_pages,data_pages獲得的結果也和前面查詢出來的結果是一致的,總分配了17個頁,使用了15個頁包括13個數據頁+1個IAM頁+1個索引頁。code

手繪一張當前表格的彙集索引體系結構圖:對象

分析索引頁blog

---DBCC page的格式爲(數據庫,文件id,頁號,顯示)
DBCC page(Ixdata,1,89,3)

 分析結果89頁下面的子頁總共有13頁,每頁80條記錄,89索引頁記錄了每頁的的鍵值的最小值,第一頁就是id爲1-80,第二頁81-160,因此當你要找ID爲150的數據的時候直接就能夠去第90頁裏面找了。索引

PAGE HEADERget

 分析數據頁

經過這些數據咱們基本上能夠知道90頁的基本狀況了,包括它的字段長度,上一頁、下一頁,還有該頁的因此記錄(這裏沒有截圖出來).

插入20萬條記錄分析索引結構 

--插入20萬條記錄分析索引結構 
DECLARE @ID INT=1
WHILE(@ID<=200000)
BEGIN
INSERT INTO Orders(NAME)VALUES('商品'+CONVERT(NVARCHAR(20),@ID))
SET @ID=@ID+1 
END




CREATE TABLE Page
(
  PageFID         TINYINT, 
  PagePID         INT,   
  IAMFID          TINYINT, 
  IAMPID          INT, 
  ObjectID        INT,
  IndexID         TINYINT,
  PartitionNumber TINYINT,
  PartitionID     BIGINT,
  iam_chain_type  VARCHAR(30),    
  PageType        TINYINT, 
  IndexLevel      TINYINT,
  NextPageFID     TINYINT,
  NextPagePID     INT,
  PrevPageFID     TINYINT,
  PrevPagePID     INT 
);
GO
INSERT INTO Page EXEC('DBCC IND(Ixdata,Orders,-1)')

---查詢索引頁
SELECT  [PageFID]
      ,[PagePID]
      ,[IAMFID]
      ,[IAMPID]
      ,[ObjectID]
      ,[IndexID]
      ,[PartitionNumber]
      ,[PartitionID]
      ,[iam_chain_type]
      ,[PageType]
      ,[IndexLevel]
      ,[NextPageFID]
      ,[NextPagePID]
      ,[PrevPageFID]
      ,[PrevPagePID]
  FROM [Ixdata].[dbo].[Page]
  WHERE PageType=2
  go
 select so.name, so.object_id, sp.index_id, internals.total_pages, internals.used_pages, internals.data_pages,first_iam_page, 
 first_page, root_page
from sys.objects so
inner join sys.partitions sp on so.object_id = sp.object_id
inner join sys.allocation_units sa on sa.container_id = sp.hobt_id
inner join sys.system_internals_allocation_units internals on internals.container_id = sa.container_id
where so.object_id = object_id('orders') 

經過兩種方法查詢到的索引頁的數量是同樣的,下面的這種計算方法是2524-2513-1(IAM頁)=10,其中807頁是root_page頁它在第二級,其它的是中間級索引頁頁就是第一級;頁能夠經過下面的16進制計算出來,IAM=5*16=80,ROOT_PAGE=3*16*16+2*16+7=807

再分析89頁

---DBCC page的格式爲(數據庫,文件id,頁號,顯示)
DBCC page(Ixdata,1,89,3)

查詢結果總共有269行,頁就是269個數據頁,orders表總共插入了201000條記錄,一個頁面存80條記錄,就須要2513個頁面和上面查詢到的data_page是同樣的。每一個索引頁存儲269個數據頁面就須要(‘select 2513*1.0/269’除不盡加1)10個索引頁,查詢最後一個索引頁2698發現它還沒分頁共存儲了361條記錄,總共8*269+361=2513

手繪存儲結構 

手繪的有點難看,可是意思差很少表達出來了。

大型對象 (LOB) 列

 根據彙集索引中的數據類型,每一個彙集索引結構將有一個或多個分配單元,將在這些單元中存儲和管理特定分區的相關數據。每一個彙集索引的每一個分區中至少有一個 IN_ROW_DATA 分配單元。若是彙集索引包含大型對象 (LOB) 列,則它的每一個分區中還會有一個 LOB_DATA 分配單元。若是彙集索引包含的變量長度列超過 8,060 字節的行大小限制,則它的每一個分區中還會有一個 ROW_OVERFLOW_DATA 分配單元。

---建立測試表
CREATE TABLE Orderslob
(ID INT PRIMARY KEY IDENTITY(1,1),
NAME CHAR(80)NOT NULL,
Product NVARCHAR(MAX) NOT NULL,
IDATE DATETIME NOT NULL DEFAULT(GETDATE())
);
GO
---插入1000條測試數據
DECLARE @ID INT=1
WHILE(@ID<=1000)
BEGIN
INSERT INTO Orderslob(NAME,Product)VALUES(CONVERT(NVARCHAR(20),@ID)+'商品',REPLICATE(@ID,2))
SET @ID=@ID+1 
END
--REPLICATE(@ID,200)
GO

DBCC IND(Ixdata,Orderslob,1)

--查看2719數據頁的信息
DBCC page(Ixdata,1,2719,1)

結果記錄了每一條記錄的偏移量。

 

每一個人在本身的電腦上面測試頁面id會不同,可是反應的結果是同樣的。

總結

  原本想所有寫完的,等寫完這部分的時候發現篇幅已經有點長了,並且本身也有的吃不消熬到1點才寫完,接下來還有中下兩部分會盡快在幾天內寫完,歡迎關注。   

 

備註:

    做者:pursuer.chen

    博客:http://www.cnblogs.com/chenmh

本站點全部隨筆都是原創,歡迎你們轉載;但轉載時必須註明文章來源,且在文章開頭明顯處給明連接,不然保留追究責任的權利。

《歡迎交流討論》

相關文章
相關標籤/搜索