說到聚集索引,我想每個碼農都明白,但是也有很多像我這樣的猥程式設計師,只能用死記硬背來解決這個問題,什麼表中只能建一個聚集索引,
然後又扯到了目錄查詢來幫助讀者記憶。。。。問題就在這裡,我們不是學文科,,,不需要去死記硬背,,,我們需要的就是能看到在眼裡面的
真實東西。。。。。我們都喜歡聚集索引,因為它能夠把無序的堆表記錄變成有序,還玩起了B樹。。。這樣就把複雜度從N降低到了LogMN。。。
這樣的話邏輯讀,物理讀就下來了。
一:現象
1:無索引的情況
還是老規矩,看個例子感受下,首先我有一個Product表,裡面沒有任何索引,如下圖:
從上圖中,我悲劇的看到了,物理讀是9次,也就說明走了9次硬碟,你也可以想到,走硬碟的目的是為了拿資料,邏輯讀有1636次,要注意的是這裡
的”次“是“頁”的意思,也就是在記憶體中走了1636個資料頁,我用dbcc ind 給你看一下,是不是有1636個表資料頁。
這裡有1637個資料頁的原因是第一個是IAM跟蹤頁。
2:有聚集索引的情況
下面我在Product表中建一個product_idx_productid的聚集索引,然後再次看看io情況,如下圖:
當你看到這個”邏輯讀“為3次的時候,你是不是已經瘋了。。。在多達1636個資料頁中找到目標資料,只需3次。。。。這個在演算法盲看來是不是神
仙下凡???當然,,,此物天上有,人間也有。。。既然有,就應該有一種非常強烈的探索欲。。。。看看這裡面到底是怎麼玩的。。。。。。
二:探索原理
1: 探索葉子節點
剛才也說了,聚集索引玩的就是B樹,既然是B樹,那就有葉子節點和分支節點,專業術語就是度為0的為葉子節點,度>0的叫做分支節點。。。。
我想你也聽說了,聚集索引是將索引列資料進行排序後放入B樹,那為了讓你眼見為實,我先建立一個ID無序的3條記錄。
insert into Person values(2,'bbbbb') insert into Person values(3,'ccccc') insert into Person values(1,'aaaaa')
然後我用dbcc ind 命令檢視下3條記錄在哪個資料頁中,如圖:
從圖中可以看到,我的三條記錄是放在148號資料頁中的,然後我匯出148號資料頁,看看內容是什麼。
dbcc traceon(3604) dbcc page(Ctrip,1,148,1)
從上圖中,我們看到了”資料頁“中的各個槽位的指向是按照表中的實際儲存記錄來的,好了,下面我建立個聚集索引,看看實際資料是不是真的有序了?
create clustered index Ctrip_idx_ID on Person(ID)
不過在這裡有個有趣的問題,我的148號”表資料頁“哪去了???也是夠奇葩的,換來的確實173號索引頁,那為了保證資料完整性,應該是把
148號資料頁的內容灌到173索引頁裡面去了吧???? 沒關係,驗證一下。
1 dbcc traceon(3604) 2 dbcc page(Ctrip,1,173,1)
通過上面的圖,有沒有直觀的感覺到? 資料現在已經是aaaaa,bbbbb,ccccc的模式了。。。有序啦。。。。同時索引頁中也儲存了148號資料
頁的欄位值,比如ID,Name資訊,拿下面的slot0槽位舉例:
到此為止,我想你對葉子節點的內容有了個大概的認識,起碼沒有讓你死記硬背了~~~
2 :探索分支節點
為了讓你看到分支節點,我得多灌一些資料進去,好歹要讓資料撐破一個索引資料頁,這樣分支節點索引資料頁就出來了,看下面的例子:
從圖中可以看到,當我插入1000條資料的時候,已經出現了一個分支節點(120號索引資料頁),三個葉子節點(173,121,126),葉子
節點的資料頁內容我也說過了,現在我很好奇”分支節點“中儲存著什麼內容???我好興奮,我要匯出120號索引資料頁了。。。
1 dbcc traceon(3604) 2 dbcc page(Ctrip,1,120,1)
簡單分析下slot0:06000000 00ad0000 000100 的內容
00000000:葉子索引頁中的最小key值(這裡有點特殊,除一行記錄不是儲存最小值以外,其餘都是的),轉換為十進位制就是0。
ad000000:葉子索引頁的頁號,轉換為十進位制就是173。
0100:葉子索引頁的檔案號,轉換為十進位制就是1.
不過通過分析,我們看到了,其實分支節點中儲存著有兩個值,一個childpage的minkey,一個childpage的pageid,同理,其他的槽位也是這樣。
我們換個引數命令,讓結果更直觀點,記錄中就是儲存著”pageID“和”minKey“。
這樣的話,我腦海中就有一張圖出來了,不知道你現在是否有了????
通過上面的分析,除了第一行記錄不是儲存子索引頁中最小key的值外,其他記錄都是提取子索引頁中的最小索引鍵值,這一點要注意。。。
也許對sqlserver團隊來說,只要判斷小於449的話就直接去(1:173)資料頁,小於889的直接去(1:121)資料頁就可以啦。。。
當你看到這裡的時候,不知道你是否已經明白,為什麼表中只能有一個聚集索引呢???好了,亂雞巴扯了好多,希望對你有所幫助。