一区二区三区日韩精品-日韩经典一区二区三区-五月激情综合丁香婷婷-欧美精品中文字幕专区

分享

SQLSERVER聚集索引與非聚集索引的再次研究(上)

 小魚(yú)兒363 2016-03-10

SQLSERVER聚集索引與非聚集索引的再次研究(上)

上篇主要說(shuō)聚集索引

下篇的地址:SQLSERVER聚集索引與非聚集索引的再次研究(下)

由于本人還是SQLSERVER菜鳥(niǎo)一枚,加上一些實(shí)驗(yàn)的邏輯嚴(yán)謹(jǐn)性,
單寫(xiě)《SQLSERVER聚集索引與非聚集索引的再次研究(上)》就用了12個(gè)小時(shí),兩篇文章加起來(lái)最起碼寫(xiě)了20個(gè)小時(shí),
本人非常非常用心的努力完成這兩篇文章,希望各位看官給點(diǎn)意見(jiàn)o(∩_∩)o

 

為了搞清楚索引內(nèi)部工作原理和結(jié)構(gòu),真是千頭萬(wàn)緒,這篇文章只是作為參考,里面的觀點(diǎn)不一定正確

有一些問(wèn)題,msdn里,網(wǎng)上的文章里,博客園里都有提到,但是這些問(wèn)題的答案是正確的嗎?其實(shí)有時(shí)候我自己都想知道答案

比如,畫(huà)聚集索引的圖,有一些人用表格來(lái)表示,但是他們正確嗎?

以前知道聚集索引 非聚集索引是B樹(shù) 二叉樹(shù)結(jié)構(gòu),又知道執(zhí)行計(jì)劃圖標(biāo)很像二叉樹(shù)很傳神,但是還是覺(jué)得很抽象

這篇文章寫(xiě)完以后還是比較抽象但是最起碼比以前清晰一些了

有很多問(wèn)題不知道為什么,但是MSDN就是這樣說(shuō)的,既然說(shuō)得這麼模糊不如自己做一下實(shí)驗(yàn),驗(yàn)證一下MSDN的內(nèi)容吧o(∩_∩)o

--------------------------------------------華麗的分割線---------------------------------------------

 先來(lái)看一下索引的結(jié)構(gòu),文章里面的一些結(jié)構(gòu)圖都是自己畫(huà)的一些草圖,本人自認(rèn)畫(huà)得非常爛,希望各位看官諒解o(∩_∩)o

 

 

 

----------------------------------------------華麗的分割線---------------------------------------------------------

先創(chuàng)建一個(gè)表,保存DBCC IND的結(jié)果

 1 CREATE TABLE DBCCResult (
 2 PageFID NVARCHAR(200),
 3 PagePID NVARCHAR(200),
 4 IAMFID NVARCHAR(200),
 5 IAMPID NVARCHAR(200),
 6 ObjectID NVARCHAR(200),
 7 IndexID NVARCHAR(200),
 8 PartitionNumber NVARCHAR(200),
 9 PartitionID NVARCHAR(200),
10 iam_chain_type NVARCHAR(200),
11 PageType NVARCHAR(200),
12 IndexLevel NVARCHAR(200),
13 NextPageFID NVARCHAR(200),
14 NextPagePID NVARCHAR(200),
15 PrevPageFID NVARCHAR(200),
16 PrevPagePID NVARCHAR(200)
17 )

創(chuàng)建一個(gè)聚集索引表

1 --只有聚集索引
2 CREATE TABLE Department(
3     DepartmentID int IDENTITY(1,1) NOT NULL PRIMARY KEY,
4     Name NVARCHAR(200) NOT NULL,
5     GroupName NVARCHAR(200) NOT NULL,
6     Company NVARCHAR(300),
7     ModifiedDate datetime NOT NULL  DEFAULT (getdate())
8 )

插入10W條記錄

1 INSERT INTO Department(name,[Company],groupname) VALUES('銷售部','中國(guó)你好有限公司XX分公司','銷售組')
2 GO 100000

將DBCC IND的結(jié)果放入DBCCRESULT表

1 INSERT INTO DBCCResult EXEC ('DBCC IND(pratice,Department,-1) ')

查詢Department表中的頁(yè)面情況

先說(shuō)明一下:

PageType  分頁(yè)類型: 1:數(shù)據(jù)頁(yè)面;2:索引頁(yè)面;3:Lob_mixed_page;4:Lob_tree_page;10:IAM頁(yè)面

IndexID    索引ID:   0 代表堆, 1 代表聚集索引, 2-250 代表非聚集索引 ,大于250就是text或image字段

紅色框部分都是需要關(guān)注的

第一個(gè):IAM頁(yè)不是只有堆表才有也不只是維護(hù)堆表中的數(shù)據(jù)頁(yè)的連續(xù),有索引的表都有,所以IAM頁(yè)不只維護(hù)數(shù)據(jù)頁(yè),也維護(hù)索引頁(yè)的連續(xù),在下篇說(shuō)到非聚集索引的時(shí)候

我會(huì)給出MSDN的解釋和IAM頁(yè)在聚集索引表,非聚集索引表中的情況

第二個(gè):每個(gè)數(shù)據(jù)頁(yè)的IndexID都是1,不是說(shuō)數(shù)據(jù)頁(yè)變成了索引頁(yè),而是說(shuō)現(xiàn)在數(shù)據(jù)頁(yè)已經(jīng)屬于聚集索引的一部分,不在堆里了

第三個(gè):每個(gè)數(shù)據(jù)頁(yè)的IndexLevel都是0,就是說(shuō)數(shù)據(jù)頁(yè)在聚集索引的最下層

第四個(gè):索引頁(yè)和數(shù)據(jù)頁(yè),前一頁(yè)和后一頁(yè)是首尾相連的,但是數(shù)據(jù)頁(yè)和索引頁(yè)不是首尾相連的,也就是說(shuō)沒(méi)有一個(gè)數(shù)據(jù)頁(yè)的[PrevPagePID]指向14464頁(yè)或3528頁(yè)

那么在上面的聚集索引圖片中為什麼會(huì)說(shuō)索引頁(yè)指向數(shù)據(jù)頁(yè)呢?葉子節(jié)點(diǎn)就是數(shù)據(jù)頁(yè)呢?

數(shù)據(jù)頁(yè)的index level是0,那么就是說(shuō)聚集索引的葉子節(jié)點(diǎn)就是數(shù)據(jù)頁(yè)

 上面索引頁(yè)的結(jié)構(gòu)

現(xiàn)在來(lái)看一下索引頁(yè)里都有什么,運(yùn)行下面的SQL語(yǔ)句

 1 DBCC TRACEON(3604,-1)
 2 GO
 3 
 4 DBCC PAGE([pratice],1,3527,3)
 5 GO
 6 
 7 
 8 DBCC PAGE([pratice],1,3528,3)
 9 GO
10 
11 DBCC PAGE([pratice],1,14464,3)
12 GO

 您們應(yīng)該看到ChildPageId,所以上面我的圖為什麼會(huì)這樣畫(huà)的原因,索引頁(yè)連接著數(shù)據(jù)頁(yè),而且一個(gè)索引頁(yè)指向多個(gè)數(shù)據(jù)頁(yè)

 DepartmentID是主鍵列,從1開(kāi)始自增,那么從下圖可以看出主鍵列數(shù)據(jù)是從最左邊的索引節(jié)點(diǎn)(不是葉子節(jié)點(diǎn))開(kāi)始排序

這里有個(gè)問(wèn)題:為什麼根節(jié)點(diǎn)只有兩行???是不是根節(jié)點(diǎn)只作連接作用,所以只有兩行 ??

答:其實(shí)我們?cè)诮⑺饕臅r(shí)候,會(huì)有一個(gè)默認(rèn)選項(xiàng):PAD_INDEX

PAD_INDEX 選項(xiàng)只作用于 非葉級(jí)索引頁(yè)

如果PAD_INDEX未指定,則默認(rèn)會(huì)為非葉級(jí)頁(yè)留出一行空間

在非葉級(jí)頁(yè)上的行數(shù)永遠(yuǎn)不會(huì)小于兩行

聚集索引頁(yè)里主鍵列DepartmentID上一行與下一行相差120條記錄,一個(gè)數(shù)據(jù)頁(yè)剛好容納120條記錄

KeyHashValue根據(jù)主鍵列的第一個(gè)字段而生成的,就算兩個(gè)表完全一樣,這個(gè)hash出來(lái)的KeyHashValue都不會(huì)一樣

我創(chuàng)建了一個(gè)一模一樣的表Department2,看到hash出來(lái)的值都不一樣

 

------------------------------------------------------------華麗的分割線------------------------------------------------------

聚集索引怎麼找記錄的???

這里要分兩種情況:(1)聚集索引查找  (2)聚集索引掃描

(1)聚集索引查找

 放大一下索引頁(yè)

 

 

SQLSERVER聚集索引查找記錄的流程

先用二分查找法找到實(shí)際的數(shù)據(jù)頁(yè)面,然后再到數(shù)據(jù)頁(yè)里把實(shí)際數(shù)據(jù)讀出來(lái)

這里還有一個(gè)keyhashvalue用來(lái)鎖定數(shù)據(jù)行資源, 運(yùn)行下面的SQL語(yǔ)句,看一下SQLSERVER申請(qǐng)的鎖就知道了

 下面實(shí)驗(yàn)我在Department2表里做的,表數(shù)據(jù)和表結(jié)構(gòu)和Department1一模一樣

View Code

 下面這個(gè)證明代碼在《SQLSERVER企業(yè)級(jí)平臺(tái)管理實(shí)踐》里找的

View Code

 

 

需要記住的是,B樹(shù)索引本身并不能找到具體的一條記錄,能找到的只是該記錄所在的頁(yè)面,數(shù)據(jù)庫(kù)把頁(yè)面載入到內(nèi)存,這里算一個(gè)讀I/O

對(duì)真?zhèn)€頁(yè)面進(jìn)行掃描,由于在內(nèi)存中查找的一個(gè)頁(yè)面里的一條記錄很快,因此通常忽略這部分掃描所用的時(shí)間

二分查找只是個(gè)縮小查找范圍的查找方法,本身作用于的對(duì)象是一個(gè)個(gè)的數(shù)據(jù)頁(yè)面,要找到具體某條記錄還需要讀取整個(gè)頁(yè)面到內(nèi)存進(jìn)行查找

 

 

(2)聚集索引掃描

先drop掉Department2表,然后重新創(chuàng)建Department2表

View Code

證明:

View Code

上圖“以下查詢使用了聚集索引查找”,由于本人寫(xiě)SQL代碼的時(shí)候沒(méi)有修改上面注釋,大家可以不用理會(huì)

為什麼會(huì)有一個(gè)鍵鎖,那么多的頁(yè)鎖,在徐海蔚老師的《SQLSERVER企業(yè)級(jí)平臺(tái)管理實(shí)踐》的書(shū)本里第361頁(yè)說(shuō)到

因?yàn)樵谟芯奂饕谋砀裆?,?shù)據(jù)是直接存放在索引的最底層(葉子節(jié)點(diǎn)),所以要掃描整個(gè)表格里的數(shù)據(jù),就要把整個(gè)聚集索引

掃描一遍。在這里,聚集索引掃描就相當(dāng)于一個(gè)表掃描。所要用的時(shí)間和資源與表掃描沒(méi)有什么差別

 

SQLSERVER不會(huì)停止掃描數(shù)據(jù)頁(yè),所以才看到上圖有那么多的頁(yè)面上加了頁(yè)鎖,SQLSERVER需要逐個(gè)數(shù)據(jù)頁(yè)逐個(gè)數(shù)據(jù)頁(yè)去掃描就像堆表的全表掃描那樣。

那個(gè)鍵鎖是當(dāng)SQLSERVER找到那條記錄之后,需要在

記錄的所在頁(yè)面(即是索引頁(yè)指向那個(gè)記錄的數(shù)據(jù)頁(yè)的那一行)加上一個(gè)鍵鎖,以防止別人刪除索引頁(yè)的那一行記錄

但是聚集索引掃描是不是一定比聚集索引查找要差呢?這個(gè)不一定,要看實(shí)際情況o(∩_∩)o

那么非聚集索引掃描是不是跟聚集索引掃描一樣,所要用的時(shí)間和資源與表掃描沒(méi)有什么差別呢???

大家可以看一下《SQLSERVER聚集索引與非聚集索引的再次研究(下)》本人做的一個(gè)小實(shí)驗(yàn)

實(shí)驗(yàn)證明了《SQLSERVER企業(yè)級(jí)平臺(tái)管理實(shí)踐》里第363頁(yè)說(shuō)到的內(nèi)容

索引掃描表明SQLSERVER正在掃描一個(gè)非聚集索引。由于非聚集索引上一般只會(huì)有一小部分字段,所以這里雖然也是掃描,但是

代價(jià)會(huì)比整表掃描要小很多

 

 ------------------------------------------------華麗的分割線--------------------------------------------------------------------

 這里有一個(gè)問(wèn)題:沒(méi)有主鍵但是有聚集索引,索引頁(yè)的列數(shù)不一樣,會(huì)多了一列,而這個(gè)列(uniquifier)的作用在下面會(huì)講到

這里創(chuàng)建Department3表

View Code

 可以看到只有聚集索引沒(méi)有主鍵的表會(huì)比主鍵表多了一列uniquifier列,這個(gè)列的作用會(huì)在創(chuàng)建Department5表的時(shí)候講到

-----------------------------------------------華麗的分割線-------------------------------------------------------

 下面說(shuō)一下,復(fù)合主鍵或者聚集索引建立在多個(gè)字段上,KeyHashValue只會(huì)根據(jù)第一個(gè)字段生成hash key

當(dāng)你查詢的時(shí)候where 后面的字段不包含創(chuàng)建聚集索引時(shí)的第一個(gè)字段或者復(fù)合主鍵的第一個(gè)字段就會(huì)聚集索引掃描而不是聚集索引查找

 創(chuàng)建Department4表

View Code

 

1 SELECT * FROM [dbo].[Department4] WHERE name='銷售部6'  --聚集索引掃描  因?yàn)閚ame不是復(fù)合主鍵中的第一個(gè)字段
2 SELECT * FROM [dbo].[Department4] WHERE name='銷售部241' AND [DepartmentID]=241  --聚集索引查找
3 SELECT * FROM [dbo].[Department4] WHERE [DepartmentID]=241   --聚集索引查找

 

 

在建立聚集索引的時(shí)候在多個(gè)字段上建立聚集索引是沒(méi)有任何意義的

因?yàn)榫奂饕檎沂歉鶕?jù)建立索引的第一個(gè)字段來(lái)查找,索引掃描的時(shí)候會(huì)到數(shù)據(jù)頁(yè)里掃描 ,而聚集索引的每一行只是一個(gè)數(shù)據(jù)頁(yè)的范圍值從而不能直接定位到要找的那條記錄

所以只需要在數(shù)據(jù)表的一個(gè)字段上建立聚集索引就可以了,而究竟要在哪一個(gè)字段上建立聚集索引大家一定好好斟酌,本人建議那一個(gè)字段在order by中經(jīng)常要排序的

因?yàn)閿?shù)據(jù)頁(yè)都已經(jīng)按照聚集索引的第一個(gè)字段排好序的了

而不像非聚集索引的索引頁(yè)跟數(shù)據(jù)表的記錄一一對(duì)應(yīng),掃描的時(shí)候掃描索引頁(yè)的每一行

大家可以對(duì)比一下聚集索引和非聚集索引頁(yè)的結(jié)構(gòu)

聚集索引頁(yè)的結(jié)構(gòu)

非聚集索引頁(yè)的結(jié)構(gòu)

非聚集索引頁(yè)面的結(jié)構(gòu)會(huì)在SQLSERVER聚集索引與非聚集索引的再次研究(下)里講到

 ---------------------------------------------------------華麗的分割線-----------------------------------------------------

 由于主鍵不允許重復(fù)值,那么就在表上創(chuàng)建一個(gè)不唯一的聚集索引,有人說(shuō)在重復(fù)值很多的列上建立聚集索引沒(méi)有意義

創(chuàng)建Department5表  在Company字段上建立聚集索引,Company字段的值全部都是"中國(guó)你好有限公司XX分公司"

View Code

 

View Code

 

在Department3表的時(shí)候講到列(uniquifier),為什麼有主鍵的表沒(méi)有這個(gè)列,而聚集索引的表有這個(gè)列,原因在于

主鍵列不能有重復(fù)值,必須是唯一的,而聚集索引允許有重復(fù)值,所以聚集索引需要增加列(uniquifier)來(lái)區(qū)分重復(fù)值

而且可以看到這里uniquifier列是沒(méi)有規(guī)律的,不像Department表每隔120行記錄在索引頁(yè)里標(biāo)記一行

看一下執(zhí)行計(jì)劃和執(zhí)行結(jié)果

 1 SET STATISTICS TIME ON
 2 SELECT * FROM [dbo].[Department5] WHERE [Company]='中國(guó)你好有限公司XX分公司' AND [DepartmentID]=241 
 3 
 4 SQL Server 分析和編譯時(shí)間: 
 5    CPU 時(shí)間 = 0 毫秒,占用時(shí)間 = 0 毫秒。
 6 
 7 (1 行受影響)
 8 
 9 SQL Server 執(zhí)行時(shí)間:
10    CPU 時(shí)間 = 0 毫秒,占用時(shí)間 = 0 毫秒。

1 SET STATISTICS TIME ON
2 SELECT * FROM [dbo].[Department5] WHERE name='銷售部106' AND [DepartmentID]=106  --聚集索引掃描
3 SQL Server 執(zhí)行時(shí)間:
4    CPU 時(shí)間 = 0 毫秒,占用時(shí)間 = 0 毫秒。

至于應(yīng)不應(yīng)該在重復(fù)值很多的列上建立聚集索引我這里也不敢妄下判斷,因?yàn)閷?shí)際環(huán)境和這里的測(cè)試環(huán)境不一樣

在MSDN中的解釋:http://msdn.microsoft.com/zh-cn/library/ms177484(v=SQL.105).aspx

如果聚集索引不是唯一的索引,SQL Server 將添加在內(nèi)部生成的值(稱為唯一值)以使所有重復(fù)鍵唯一。此四字節(jié)的值對(duì)于用戶不可見(jiàn)

還有一個(gè),看一下葉子節(jié)點(diǎn)中的數(shù)據(jù)頁(yè),在每個(gè)數(shù)據(jù)頁(yè)的每行記錄中都有

Slot 101 Column 0 Offset 0x1d Length 4

UNIQUIFIER = 206 

因?yàn)樾枰獦?biāo)記索引列中的唯一,所以需要在每行記錄中增加一列UNIQUIFIER ,但是這一列在select * 表中數(shù)據(jù)的時(shí)候是select不出來(lái)的

還有人說(shuō)UNIQUIFIER 是一個(gè)可變長(zhǎng)度的字段,但是Length 4已經(jīng)說(shuō)明了是一個(gè)占用4字節(jié)的字段

View Code

還有增加了UNIQUIFIER 列之后,無(wú)論索引頁(yè)和數(shù)據(jù)頁(yè)都會(huì)有所增加,性能有所損耗

下面截圖右邊的是數(shù)據(jù)頁(yè)pageid:14517中的數(shù)據(jù),左邊的是聚集索引頁(yè)面

至于性能損耗多少,可以看一下宋大俠這篇文章:

從性能的角度談SQL Server聚集索引鍵的選擇

----------------------------------------------------華麗的分割線-------------------------------------------------------

 堆表中的數(shù)據(jù)頁(yè)之間[PrevPagePID],[NextPagePID]是否會(huì)首尾相連

堆表

聚集索引表

 -----------------------------------------------------華麗的分割線-------------------------------------------------

聚集索引有一個(gè)特點(diǎn),就是當(dāng)表記錄太少的時(shí)候,可能一個(gè)數(shù)據(jù)頁(yè)面就能容納下表的所有記錄,那么這時(shí)候由于可能只有一個(gè)頁(yè)面不足以構(gòu)成一棵B樹(shù)

創(chuàng)建Department6表,然后插入9條記錄

 1 --只有聚集索引
 2 USE [pratice]
 3 GO
 4 CREATE TABLE Department6
 5 (
 6   DepartmentID INT IDENTITY(1, 1) NOT NULL ,
 7   Name NVARCHAR(200) NOT NULL ,
 8   GroupName NVARCHAR(200) NOT NULL ,
 9   Company NVARCHAR(300) ,
10   ModifiedDate DATETIME NOT NULL DEFAULT ( GETDATE() ) ,
11   CONSTRAINT [PK_Department6_1] PRIMARY KEY CLUSTERED
12     (  Name ASC,DepartmentID ASC )
13     WITH ( PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF,
14            ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON ) ON [PRIMARY]
15 ) ON [PRIMARY]
16 
17 
18 DECLARE @i INT
19 SET @i=1
20 WHILE @i < 10
21     BEGIN
22         INSERT  INTO Department6 ( name, [Company], groupname )
23         VALUES  ( '銷售部'+CAST(@i AS VARCHAR(200)), '中國(guó)你好有限公司XX分公司', '銷售組' )
24         SET @i = @i + 1
25     END

只有一個(gè)數(shù)據(jù)頁(yè)和一個(gè)IAM頁(yè)

插入更多記錄

1 DECLARE @i INT
2 SET @i=1
3 WHILE @i < 100000
4     BEGIN
5         INSERT  INTO Department6 ( name, [Company], groupname )
6         VALUES  ( '銷售部'+CAST(@i AS VARCHAR(200)), '中國(guó)你好有限公司XX分公司', '銷售組' )
7         SET @i = @i + 1
8     END

因?yàn)閿?shù)據(jù)頁(yè)開(kāi)始多起來(lái)了,這時(shí)候聚集索引會(huì)組織會(huì)一棵有層次結(jié)構(gòu)的B樹(shù)

IndexLevel為2  表示這棵B樹(shù)有3層

0:葉子節(jié)點(diǎn)層

1:非葉子節(jié)點(diǎn)層

2:root層

PageType 分頁(yè)類型: 1:數(shù)據(jù)頁(yè)面;2:索引頁(yè)面;3:Lob_mixed_page;4:Lob_tree_page;10:IAM頁(yè)面

IndexID 索引ID: 0 代表堆, 1 代表聚集索引, 2-250 代表非聚集索引 ,大于250就是text或image字段


---------------------------------------------華麗的分割線---------------------------------------------------

大家再看一下Department2表的那部分,究竟數(shù)據(jù)頁(yè)的排序順序跟主鍵DepartmentID的排序順序有沒(méi)有關(guān)系呢?

先創(chuàng)建Department7表,插入1000條記錄

View Code
1 --TRUNCATE TABLE [dbo].[DBCCResult]
2 INSERT INTO DBCCResult EXEC ('DBCC IND(pratice,Department7,-1) ')
3 
4 SELECT * FROM [dbo].[DBCCResult] ORDER BY [PageType] DESC 


根據(jù)數(shù)據(jù)頁(yè)的首尾連接順序,我畫(huà)了一下草圖

看一下索引頁(yè)13791

View Code

再畫(huà)一下草圖

對(duì)比一下數(shù)據(jù)頁(yè)的首尾連接順序那張圖,不知道大家看出規(guī)律沒(méi)有

所以我把聚集索引結(jié)構(gòu)圖畫(huà)成下面這個(gè)樣子

為什麼聚集索引只能按照第一個(gè)字段生成key?為什麼數(shù)據(jù)頁(yè)只能按照第一個(gè)字段來(lái)排序?

其實(shí)這個(gè)跟數(shù)據(jù)頁(yè)排序有關(guān)的,大家再仔細(xì)看下面兩張圖

聚集索引頁(yè)里根據(jù)第一個(gè)字段排列好這些數(shù)據(jù)頁(yè)的第一個(gè)字段的范圍值,數(shù)據(jù)頁(yè)根據(jù)這個(gè)范圍值首尾相連一一排序好

如果聚集索引按多個(gè)字段來(lái)排序,那么數(shù)據(jù)頁(yè)根本排不了,多個(gè)字段又升序,又降序??那怎么排序???只能按照一個(gè)字段來(lái)排序

聚集索引查找的時(shí)候,使用order by為什麼這么快,因?yàn)閿?shù)據(jù)已經(jīng)根據(jù)索引第一個(gè)字段排好序了,例子中的字段就是DepartmentID

而只有非聚集索引的表order by的時(shí)候就需要排一下序了,因?yàn)楸碇袥](méi)有聚集索引,數(shù)據(jù)頁(yè)沒(méi)有預(yù)先按照一定順序來(lái)排序

詳細(xì)可以看一下非聚集索引的結(jié)構(gòu):SQLSERVER聚集索引與非聚集索引的再次研究(下)

---------------------------------------------華麗的分割線--------------------------------------------------------

問(wèn)題:為什么一個(gè)表只能建立一個(gè)聚集索引

其實(shí)大家看一下我上面畫(huà)的聚集索引結(jié)構(gòu)圖和非聚集索引結(jié)構(gòu)圖就知道了

因?yàn)槿绻粋€(gè)表有聚集索引,那么他的數(shù)據(jù)頁(yè)跟索引頁(yè)有非常強(qiáng)的聯(lián)系,數(shù)據(jù)頁(yè)跟主鍵第一個(gè)字段排好序了,例子中就是“DepartmentID”

如果你再建一個(gè)聚集索引,你叫SQLSERVER應(yīng)該按哪個(gè)字段來(lái)排序?排序方式是按照你原來(lái)的那個(gè)聚集索引的DepartmentID列來(lái)排序還是

按照你新建的那個(gè)聚集索引的第一個(gè)字段來(lái)排序??

多個(gè)聚集索引,數(shù)據(jù)頁(yè)都按不同的字段順序排序,來(lái)建立雙向鏈表,那數(shù)據(jù)表不就亂套了???

但是如果一個(gè)表中只有非聚集索引,非聚集索引里的索引頁(yè)的每一行會(huì)有一個(gè)指針值指向數(shù)據(jù)頁(yè),數(shù)據(jù)頁(yè)依然是堆,沒(méi)有任何順序可言

所以你可以在一個(gè)表上建立多個(gè)非聚集索引也沒(méi)問(wèn)題

至于表里面只有非聚集索引表結(jié)構(gòu)是怎樣的,大家可以看一下本系列的《SQLSERVER聚集索引與非聚集索引的再次研究(下)》

到時(shí)大家就會(huì)更加清楚了o(∩_∩)o

----------------------------------------------華麗的分割線----------------------------------------------------------


還有一個(gè)問(wèn)題沒(méi)有解決:

為什麼根節(jié)點(diǎn)只有兩行???是不是根節(jié)點(diǎn)只作連接作用,所以只有兩行 ?

 

聚集索引就說(shuō)到這里了,有些地方有可能不對(duì),希望大家強(qiáng)烈拍磚o(∩_∩)o

也希望給個(gè)推薦o(∩_∩)o

---------------------------------------------------------------------------

2013-7-21補(bǔ)充

為什麼根節(jié)點(diǎn)只有兩行??其實(shí)根節(jié)點(diǎn)不只有兩行的

由于出現(xiàn)二層索引節(jié)點(diǎn)需要插入大量數(shù)據(jù),如果數(shù)據(jù)很少的話索引節(jié)點(diǎn)只有一層,并且不能用主鍵,只能創(chuàng)建聚集索引

根據(jù)宋大俠說(shuō)的,當(dāng)頁(yè)拆分的時(shí)候,根節(jié)點(diǎn)就會(huì)增加記錄,我這里提供一下腳本

 

 1 USE [pratice]
 2 GO
 3 --------------------------------------------------------------------
 4 --只有聚集索引
 5 --DROP TABLE [dbo].[Department]
 6 CREATE TABLE Department(
 7     DepartmentID int  NOT NULL ,
 8     Name NVARCHAR(200) NOT NULL,
 9     GroupName NVARCHAR(200) NOT NULL,
10     Company NVARCHAR(300),
11     ModifiedDate datetime NOT NULL  DEFAULT (getdate())
12 )
13 
14 CREATE CLUSTERED INDEX CL_DepartmentID ON Department(DepartmentID ASC)
15 
16 DECLARE @i INT
17 SET @i=1
18 WHILE @i < 300000
19     BEGIN
20         INSERT  INTO Department([DepartmentID], name, [Company], groupname )
21         VALUES  ( @i,'銷售部'+CAST(@i AS VARCHAR(200)), '中國(guó)你好有限公司XX分公司', '銷售組'+CAST(@i AS VARCHAR(200)) )
22         SET @i = @i + 3
23     END
24 
25 --DROP TABLE Department
26 SELECT * FROM Department
27 
28 
29 
30 --TRUNCATE TABLE [dbo].[DBCCResult]
31 INSERT INTO DBCCResult EXEC ('DBCC IND(pratice,Department,-1) ')
32 
33 SELECT * FROM [dbo].[DBCCResult] ORDER BY [PageType] DESC 

大家可以測(cè)試一下

插入數(shù)據(jù)的時(shí)候最好是根節(jié)點(diǎn)前的記錄

附上宋大俠的文章:

T-SQL查詢高級(jí)—SQL Server索引中的碎片和填充因子

根節(jié)點(diǎn)的記錄行數(shù)在下面兩種情況下會(huì)有所變化

(1)向表中插入數(shù)據(jù)或更新表中數(shù)據(jù)并產(chǎn)生碎片的時(shí)候

(2)碎片很多然后alter index REORGANIZE 重組索引的時(shí)候

1 ALTER INDEX [dbo].[TableForTest].[CIX] ON [dbo].[Department] REORGANIZE

 ------------------------------------------------------------------------------

2013-8-24  補(bǔ)充:

關(guān)于我在文中說(shuō)的

至于應(yīng)不應(yīng)該在重復(fù)值很多的列上建立聚集索引我這里也不敢妄下判斷,因?yàn)閷?shí)際環(huán)境和這里的測(cè)試環(huán)境不一樣

 

今天看了一下《SQLSERVER企業(yè)級(jí)平臺(tái)管理實(shí)踐》,書(shū)里面第437頁(yè)是這樣說(shuō)的

要慎重選擇索引的第一個(gè)字段,最好選擇一個(gè)重復(fù)記錄最少的字段。這是因?yàn)樗饕系慕y(tǒng)計(jì)信息只保存第一個(gè)字段的數(shù)據(jù)直方圖。如果選擇一個(gè)

重復(fù)數(shù)據(jù)很多的字段,這個(gè)索引的可選度就比較低了,會(huì)影響索引的價(jià)值

 

所以,為什麼建立聚集索引的時(shí)候,只能在一個(gè)字段上建立索引,并且這個(gè)字段最好不要重復(fù),從數(shù)據(jù)直方圖上也能解釋這個(gè)原因

------------------------------------------------------------------------------------------

2013-9-15 補(bǔ)充:

如何查看聚集索引頁(yè)面的內(nèi)容,使用DBCC PAGE的時(shí)候使用1這個(gè)格式就可以了

聚集索引頁(yè)中有三條記錄,而且三條記錄的Record Type = INDEX_RECORD

1 DBCC TRACEON(3604,-1)
2 GO
3 DBCC PAGE([pratice],1,37397,1)
4 GO

 1 DBCC 執(zhí)行完畢。如果 DBCC 輸出了錯(cuò)誤信息,請(qǐng)與系統(tǒng)管理員聯(lián)系。
 2 
 3 PAGE: (1:37397)
 4 
 5 
 6 BUFFER:
 7 
 8 
 9 BUF @0x03E5DC3C
10 
11 bpage = 0x1A8D8000                   bhash = 0x00000000                   bpageno = (1:37397)
12 bdbid = 5                            breferences = 0                      bUse1 = 6487
13 bstat = 0x3c0000b                    blog = 0x212159bb                    bnext = 0x00000000
14 
15 PAGE HEADER:
16 
17 
18 Page @0x1A8D8000
19 
20 m_pageId = (1:37397)                 m_headerVersion = 1                  m_type = 2
21 m_typeFlagBits = 0x0                 m_level = 1                          m_flagBits = 0x0
22 m_objId (AllocUnitId.idObj) = 549    m_indexId (AllocUnitId.idInd) = 256  
23 Metadata: AllocUnitId = 72057594073907200                                 
24 Metadata: PartitionId = 72057594061717504                                 Metadata: IndexId = 1
25 Metadata: ObjectId = 1543676547      m_prevPage = (0:0)                   m_nextPage = (0:0)
26 pminlen = 11                         m_slotCnt = 3                        m_freeCnt = 8057
27 m_freeData = 129                     m_reservedCnt = 0                    m_lsn = (3046:261:41)
28 m_xactReserved = 0                   m_xdesId = (0:0)                     m_ghostRecCnt = 0
29 m_tornBits = 0                       
30 
31 Allocation Status
32 
33 GAM (1:2) = ALLOCATED                SGAM (1:3) = ALLOCATED               
34 PFS (1:32352) = 0x60 MIXED_EXT ALLOCATED   0_PCT_FULL                     DIFF (1:6) = CHANGED
35 ML (1:7) = NOT MIN_LOGGED            
36 
37 DATA:
38 
39 
40 Slot 0, Offset 0x60, Length 11, DumpStyle BYTE
41 
42 Record Type = INDEX_RECORD           Record Attributes =                  
43 Memory Dump @0x0A3BC060
44 
45 00000000:   06010000 00283d00 000100?????????????.....(=....              
46 
47 Slot 1, Offset 0x6b, Length 11, DumpStyle BYTE
48 
49 Record Type = INDEX_RECORD           Record Attributes =                  
50 Memory Dump @0x0A3BC06B
51 
52 00000000:   06950100 00929100 000100?????????????...........              
53 
54 Slot 2, Offset 0x76, Length 11, DumpStyle BYTE
55 
56 Record Type = INDEX_RECORD           Record Attributes =                  
57 Memory Dump @0x0A3BC076
58 
59 00000000:   06290300 002f0000 000100?????????????.).../.....              
60 
61 OFFSET TABLE:
62 
63 Row - Offset                         
64 2 (0x2) - 118 (0x76)                 
65 1 (0x1) - 107 (0x6b)                 
66 0 (0x0) - 96 (0x60)                  
67 
68 
69 DBCC 執(zhí)行完畢。如果 DBCC 輸出了錯(cuò)誤信息,請(qǐng)與系統(tǒng)管理員聯(lián)系。

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多

    国产中文字幕一二三区| 成人国产激情在线视频| 亚洲欧洲精品一区二区三区| 黄色污污在线免费观看| 日本不卡一区视频欧美| 免费黄片视频美女一区| 草草视频福利在线观看| 中文人妻精品一区二区三区四区| 国产av一区二区三区四区五区| 麻豆亚州无矿码专区视频| 中文日韩精品视频在线| 在线免费国产一区二区三区| 欧美人妻盗摄日韩偷拍| 三级高清有码在线观看| 99热在线精品视频观看| 年轻女房东2中文字幕| 在线观看国产午夜福利| 亚洲伦片免费偷拍一区| 欧美日韩国产成人高潮| 我想看亚洲一级黄色录像| 五月天六月激情联盟网| 超薄肉色丝袜脚一区二区| 国产精品一区二区三区日韩av| 欧美激情视频一区二区三区| 欧美韩日在线观看一区| 一级片二级片欧美日韩| 中文字幕高清免费日韩视频| 国产亚洲中文日韩欧美综合网 | 亚洲国产精品久久琪琪| 在线观看欧美视频一区| 欧美亚洲国产日韩一区二区| 久久99国产精品果冻传媒| 色婷婷激情五月天丁香| 国产精品成人免费精品自在线观看| 夜夜躁狠狠躁日日躁视频黑人| 国产精品色热综合在线| 国产精品一区二区有码| 空之色水之色在线播放| 人人妻人人澡人人夜夜| 亚洲天堂精品一区二区| 国产美女精品午夜福利视频|