SQL Server2005中的IAM鏈

SQL Server2005中的IAM鏈


原文地址:
http://blogs.msdn.com/b/sqlserverstorageengine/archive/2006/06/25/under-the-covers-iam-chains-and-allocation-units-in-sql-server-2005.aspx

現在,我們開始IAM鏈的第二部分。
昨天,我解釋了什麼是IAM鏈和在SQL SERVER 2000中是如何和索引相配對的。一個表可以有一個堆或聚集索引,可有249個非聚集索引,可有一個LOB索引(一般稱爲TEXT索引),這就是說SQL SERVER 2000中,一個表中最多有251個IAM鏈。
在SQL SERVER 2005中,IAM鏈和IAM頁與SQL SERVER 2000中是一模一樣的,但是現在一個表可以擁有750000條IAM鏈!喔,我們到底幹了什麼?

現在IAM鏈爲三類東西映射分配空間:
1.堆和B樹(B樹是系統用來存儲索引的內部結構)
2.LOB數據
3.行溢出數據

我們稱這些分配空間的單元爲分配單元(allocation units),這三類分配單元的相應的內部名稱爲:
1.HOBT分配單元(發音和指環王中的霍比特人一樣)
2.LOB分配單元
3.SLOB分配單元(SMALL –LOB)
對應的外部名稱爲:
1.IN_ROW_DATA分配單元
2.LOB_DATA分配單元
3.ROW_OVERFLOW_DATA分配單元

讓我們來看看引起變化的SQL SERVER 2005的新增的3個特性,這些特性增加了每個表的IAM鏈數目的潛力。

一.包含列
這項功能可以在非聚集索引的葉節點中包含非鍵列。這條特性因爲下面三個原因所以非常有用:
1.當查詢結果包含超過16列或者所有列的總長度大於900字節時,它允許一個非聚集索引真正地覆蓋一個查詢(還記得嗎?在SQL SERVER中,一個非聚集索引鍵不能超過16列且不能超過900個字節。)。
2.它允許不能作爲索引鍵的數據類型包含在非聚集索引(比如text或者XML類型)中。
3.它允許一個非聚集索引覆蓋一個查詢而又不需要所有的查詢列都作爲索引鍵列。因爲索引鍵會包含在B樹的所有層的行中,所以包含列可以使得索引佔用的空間更小。

舉個節省空間的例子:假設有一個1億行的索引,其鍵長度爲900字節,但是實際上只有前面2個整數需作爲索引鍵,其它4個固定列可以作爲包含列。
一個900字節的索引,那麼1頁只能包含8行(比如,fanout爲8)。這就是說葉節點需要12500000頁,上一層爲1562500頁……做個彙總,一共需要12500000 + 1562500 + 195313 + 24415 + 3052 + 382 + 48 + 6 + 1 = 14285717頁(包括葉節點以上層的1785717頁)。
如果我們使用包含列的方法使得鍵縮爲8個字節,那麼B樹的葉節點以上層一行大小爲15字節(包含了一些行的負載,這樣fanout約爲537)。注意葉節點的fanout還是8,因爲存儲在葉節點上的數據是一樣的。這樣還是12500000頁葉節點,但是上一層結點爲23278頁。所以總的爲:12500000 + 23278 + 44 + 1 = 12523323頁(包括葉節點以上層的23323頁)。和上面的900字節的鍵比較,這節省了1762394頁(12%)或者13.6GB。當然這個例子有點誇張,但是節省空間是顯而易見的。

跑點題,其實增加包含列這種特性的主要原始是可以真正地覆蓋查詢。一個覆蓋查詢是指查詢優化器知道從一個非聚集索引中得到所有查詢結果,所以就沒有必要使用額外的IO從基表中查詢數據就能滿足查詢,這是非常重大的性能節省。

現在非聚集索引有了包含列,這些列可以是LOB數據類型。這就是說SQL SERVER 2005再也沒有必要有一個單獨的LOB分配單元(在SQL SERVER 2000中有一個單獨的text索引)了,因爲每個索引都有自己的LOB組了。你可能會問我們爲什麼沒有增加單獨一組LOB,然後讓各個索引和基表指向這些LOB列?我們確實曾經考慮過,但發現它會使問題更加複雜。
所以,有了這個特性,每個索引需要兩個分配單元——一個是爲數據或索引(HOBT分配單元),一個爲任意的LOB數據。

二.巨行(Large Rows)
一個一直折磨架構設計師的問題是表的行大小的8060字節限制。在SQL SERVER 2005中,我們去除了這個限制。我們解決這個問題的方法是當行的長度太長以至於不能放在一個單獨的頁中,允許系統把變化長度列(如varchar, sqlvariant)擠出行去。
那麼這些列的值被擠到什麼地方去呢?我們有效地將它轉換成小的LOB列。行中列值由一個指向擠出列值的16字節指針所代替,擠出列就好像是一個LOB值被存儲在一個獨立的分配單元——行溢出分配單元(SLOB)中。這些值和正規的LOB值一樣存儲在text頁中,只不過用的是一個獨立的分配單元,只要當行中有一列被擠出時就會創建SLOB分配單元。
這種巨行特性同樣適用於非聚集索引。如果你考慮在非聚集索引中使用包含列,那麼你的非聚集索引很容易超過一個頁的大小。如果不在非聚集索引上使用行溢出特性,那麼我們將剛擺脫了900字節的限制,又會有8060字節的限制了。
現在有了這些特性,每個索引能有三個分配單元——HOBT、LOB和SLOB。即使這樣,一個表最多也就是有750個IAM鏈啊(記住IAM鏈現在用來映射分配單元了,所以250個索引*3個分配單元=750個IAM鏈)。但是我前面提到每個表有750000個IAM啊——剩下的是從哪兒來啊?

三.分區
分區給了我們1000倍的能力。可能你早就知道了,SQL SERVER 2005中新增的分區特性使表和索引能被分割成一系列的段,每個段被單獨存儲(更常見的是被存儲在單獨的文件組中)。分區需要另一文介紹。
如果表或索引的每個段或分區是單獨存儲的,那麼每個存儲就需要它自己的HOBT分配單元。當然,每個分區可以存儲LOB值,所以每個分區需要一個LOB分配單元。還有每個行的行溢出特性,就像未分區時表和索引一樣,每個分區中的行會溢出至SLOB分配單元中。所以每個表或索引的分區都能有3個分配單元(,也就有了3個IAM鏈)。
那麼1000倍是從哪兒來的呢?這是因爲每個表或索引可以有1000個分區。就是250索引*1000分區*3個分配單元=750000個IAM鏈。現實中這可能並不會發生,這只是一種可能性。

現在你已經知道SQL SERVER 2000和2005中一些內部結構了,希望這對理解我以後的文章有所幫助。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章