當索引包含查尋中所有的列,我們通常說索引包含查尋,任何時候發生這種情況時,DB2優化器通常選擇只訪問查尋所需的索引,稱為的純索引訪問或索引覆蓋。但“通常”並不意味著“總是”。例如,讓我們考慮下面的圖表結構:
CREATETABLECONTACT(
ZIPCODEINTNOTNULL,
PHONE_NUMBERCHAR(10)NOTNULL,
SOME_OTHER_STUFFVARCHAR(100));
CREATEINDEXCONTACT_ZIP_PHONEONCONTACT(ZIPCODE,PHONE_NUMBER);
CREATEINDEXCONTACT_PHONEONCONTACT(PHONE_NUMBER);
Letusconsiderthisquery:
SELECTZIPCODE,PHONE_NUMBERFROMCONTACTWHEREPHONE_NUMBERLIKE'312987654%'ANDZIPCODE='60606'
很明顯索引CONTACT_ZIP_PHONE並不覆蓋查尋,但DB2優化器並沒有用它。而是通過另一個索引“CONTACT_PHONE”來訪問這個圖表,這使我們有些吃驚,是吧?實際上這個決定很有意義,DB2優化器非常強力地尋找最好的訪問計劃。讓我們理解為什麼DB2優化器的決定確實是好。一方面,符合條件ZIPCODE='60606'的行數超過15,000行,另一方面,符合PHONE_NUMBERLIKE'312987654%'的行數不超過10行。這意味著PHONE_NUMBER的條件更有選擇性。有一個著名的經驗說法是:“將最有選擇性的列放在索引定義的前面”。讓我們對實際執行成本進行仔細的研究,了解這個理論(優化器)是否是對的:
讀取了兩個索引頁面,一個是根索引頁面,另一個是葉級別頁面
讀取了10個數據頁面,因為10匹配散布在圖表中的行的數量
現在讓我們進行一下“如果怎樣”的分析,讓我們先去掉CONTACT_PHONE索引再執行同樣的查尋,
現在DB2優化器在掃描索引CONTACT_ZIP_PHONE的部分,從值'60'或之後開始,掃描到'61',實際執行成本明顯高得多。
掃描多於100個葉級別頁面
正如我們看到的,優化器明智地選擇不使用覆蓋索引。
現在讓我們回到剛才提過的經驗說法:“將最有選擇性的列放在索引定義的前面”,正如我們所討論的,在大多數情況下是對的。但也有幾種例外,讓我們想象一個例子,為了開始,我們先生成一個在定義中有這種最高選擇性的索引。
SELECTZIPCODE,PHONE_NUMBERFROMCONTACTWHEREZIPCODE='60606'
如果讓選擇這兩個索引,DB2優化器將最有可能選擇在(ZIPCODE,PHONE_NUMBER)的索引。在執行過程中,只有索引部分被檢查以支持查尋。如果取消這個索引,DB2數據庫引擎將通過檢查在(PHONE_NUMBER,ZIPCODE)的整個索引來確保查尋,那樣肯定會慢些的。如果這個查尋經常執行,那采用(ZIPCODE,PHONE_NUMBER)的索引是對的。
正如我們看到的,經驗說法“將最有選擇性的列放在索引定義的前面”只是一個建議。是的,這是很好的建議,在多數情況下它是對的。但當將最有選擇性的列放在索引定義的後面的情況也會發生,在特殊情況下進行仔細的思考做出自己的決定。
關於作者:AlexanderKuznetsov有15年軟件設計,開發和數據庫管理的經驗。目前他在改善在數千兆字節數據庫環境下運行的應用程序的性能。Alexander是IBM認證的高級技術專家(群集)和IBM認證解決方案專家(數據庫管理和應用開發)。
讀者IudithM寫到:
上面所描述的問題裡,ZIPCODE列是較少有性質性的,但不是最有選擇性的,因為它返還了更高比例的行數。
當作者認為“將最有選擇性的列放在索引定義的前面”只是經驗之談是正確的觀點,但不是根據選擇性,而是基於圖表中不同行的不同具體位置對整體性能的影響的事實。
在更具選擇性列選擇比較少選擇性列的索引的性能要低。例如,由第一個索引所返還的“較少”的行會散落到許多數據區中,而由第二個索引返還的“較多”的行將集中在較少的數據區中。
所以應當對不同的情況在特定環境下進行分別測試。
[email protected]:(010)68476636)