上個(gè)星期我討論了SQL Server里的聚集索引。當(dāng)你在表上定義了一個(gè)聚集索引,你是物理上把你的表數(shù)據(jù)按提供的聚集鍵列的順序存儲(chǔ)。在SQL Server里,一個(gè)表只能定義一個(gè)聚集索引,非聚集索引可以定義多個(gè)(最多999個(gè))。
非聚集索引是第二索引,你可以在表上列進(jìn)行定義。你也可以把非聚集索引與書比較。但是這次你把它認(rèn)為類似T-SQL 語(yǔ)言參考的書。書本身就是一個(gè)聚集索引,不同的T-SQL命令是按它們的名字物理排序的。在書的最后,你會(huì)看到一個(gè)索引。當(dāng)你查找一個(gè)T-SQL 命令(例如 CREATE TABLE),你可以使用書最后的索引,來(lái)找到這個(gè)命令詳細(xì)介紹的位置。
這里書會(huì)給你一個(gè)查找值——頁(yè)碼,在那里你可以找到這個(gè)命令的詳細(xì)信息。這與SQL Server里(非聚集索引)的概念是一樣的:但給你在執(zhí)行計(jì)劃里通過(guò)非聚集索引訪問(wèn)你的表,SQL Server會(huì)在非聚集索引的葉子層給你查找值,你可以用它找到這條記錄的更多信息。SQL Server需要用這個(gè)查找值做導(dǎo)航,從非聚集索引到聚集索引或堆表里找到記錄其他列值,這些列不是非聚集索引的一部分。在SQL Server里這個(gè)被稱為書簽查找(Bookmark Lookup)。我們來(lái)看看它的更多細(xì)節(jié)。
書簽查找(Bookmark Lookups)每次不在查詢的執(zhí)行計(jì)劃里訪問(wèn)非聚集索引,你查詢里的一些列不是非聚集索引的一部分,SQL Server需要在執(zhí)行計(jì)劃里進(jìn)行書簽查找操作。下圖是一個(gè)執(zhí)行計(jì)劃里典型的書簽查找:
可以看到,SQL Server在Person.Address表里進(jìn)行非聚集查找操作。另外SQL Server通過(guò)鍵查找(Key Lookup)(聚集的)操作從聚集表獲取所有其他列。這個(gè)看起來(lái)是SQL Server里很酷的功能,但是實(shí)際上,書簽查找是非常,非常,非常危險(xiǎn)的!
它們會(huì)導(dǎo)致書簽查找死鎖,性能會(huì)受老的過(guò)期的統(tǒng)計(jì)信息影響,當(dāng)你與參數(shù)嗅探問(wèn)題(Parameter Sniffing)打交道時(shí)也是。書簽查找只會(huì)在與非聚集索引組合時(shí)發(fā)生。因此,下星期我們會(huì)討論下在執(zhí)行計(jì)劃里如何避免書簽查找,還有為什么有時(shí)候SQL Server會(huì)完全忽略你的近乎完美的非聚集索引。
聚集鍵依賴關(guān)系(Clustered Key Dependency)像我剛才說(shuō)過(guò)的,SQL Server在非聚集索引的葉子層保存查找值,用來(lái)指向存在聚集表或堆表的記錄。當(dāng)你在堆表定義了一個(gè)非聚集索引,這個(gè)查找值稱為行標(biāo)識(shí)者(Row-Identifier)查找值。它是8 bytes長(zhǎng)的值,包含記錄物理存儲(chǔ)的頁(yè)號(hào)(4 bytes),文件號(hào)(2 bytes),還有槽號(hào)(2 bytes)。
如果你在聚集表上定義你的非聚集索引,SQL Server使用聚集鍵值作為查找值。這意味你你要認(rèn)真選擇的聚集鍵列都是每個(gè)非聚集索引的一部分。在聚集和非聚集索引之間有著巨大的依賴關(guān)系。聚集鍵基本上是你表里的冗余數(shù)據(jù)。因此,當(dāng)你選擇聚集鍵列時(shí),你真的需要認(rèn)真考慮。因?yàn)樗膹?qiáng)大依賴性,選擇的最佳聚集鍵應(yīng)該有3個(gè)特性:
用心記住它們,因?yàn)槟愕木奂I始終出現(xiàn)在每個(gè)非聚集索引里。
小結(jié)非聚集索引對(duì)提高你的查詢性能非常重要。不好非聚集索引的設(shè)計(jì)會(huì)讓你引入書簽查找,這會(huì)引入巨大的問(wèn)題和副作用到你的數(shù)據(jù)庫(kù)里。如果你想對(duì)非聚集索引內(nèi)部結(jié)構(gòu)有更深入的理解,可以看看下列文章
按照我們的約定,下星期我會(huì)講下使用覆蓋非聚集索引(Covering Non-Clustered Indexes)來(lái)避免書簽查找(Bookmark Lookups)。還有臨界點(diǎn)(Tipping Point),它用來(lái)定義SQL Server是否在使用非聚集索引。請(qǐng)繼續(xù)關(guān)注!
新聞熱點(diǎn)
疑難解答
圖片精選