DB2資料庫查詢過程(Query Processing)----複合索引的匹配索引掃描(Matching Index Scans with Composite Indexs)
複合索引(Composite Index)
索引列(搜尋碼)由多個表列共同組成的索引稱為複合索引,相對的,索引列僅是單個表列的索引稱為單列索引。
例如語句:CREATE INDEX PHONEBOOK_IDX ONPHONEBOOK ( LASTNAME, FIRSTNME) 建立的索引PHONEBOOK_IDX的索引列由LASTNAME列和FIRSTNME列構成,就是一個複合索引。
複合索引和單列索引在結構上沒有什麼本質的區別,索引樹的構建和掃描也沒有什麼特別之處。就像是表的主鍵,不管是單列主鍵還是多列主鍵,等同看待就完了。
但是複合索引有一個特性:索引中的索引列(或者說搜尋碼)是有序的!這個特性非常重要!
複合索引在進行B+樹構建時的規則是:首先按照第一個索引列的值進行排序,當第一個索引列的值相同時才按照第二個索引列值進行進一步區分,當第二個索引列值扔相同再參考第三個索引列。。。以此類推。也就是說,第一索引列的值是嚴格排序的,後面的索引列值只有在前面的索引列都嚴格排序後才可能進行排序。
那麼,進行索引查詢的時候,就必須首先參照第一索引列才能進行自根向葉的高效查詢,如果沒有第一索引列作為篩選條件,就只能對索引的葉結點頁進行逐個遍歷(因為其他的索引列不能保證在B+樹中是有序的),這種情形就是前面介紹的非匹配索引掃描了。
複合索引的第一個索引列就稱為主索引列,其他的列稱為從索引列。
舉個例子:
對於表PHONEBOOK建立了一個LASTNAME,FIRSTNME列上的索引NAME_IDX(LASTNAME,FIRSTNME)。NAME_IDX索引的B+樹結構如圖:
現在有SQL查詢:
Select * From PHONEBOOK Where LASTNAME = 'Smith' and FIRSTNME = 'Steve'
那麼查詢的過程就如青色箭頭所示,根據主索引列LASTNAME的值Smith和根結點頁的邏輯指標找到第3個葉結點頁(Peters<Smith<Zidler,使用LASTNAME為Smith的索引項在第3個葉結點頁上),複合條件的索引項有兩個Smith,Stanley和Smith,Steve(這兩個索引項上有序的),然後根據從索引列FIRSTNME的值篩選出唯一符合條件的索引項Smith,Steve,繼而找到對應的資料頁。
而如果沒有FIRSTNME = 'Steve'這個條件謂詞,還是能夠按照上圖的路線找到符合條件的兩個索引項,繼而找到對應資料頁。
但是如果沒有LASTNAME = 'Smith' 這個謂詞,即查詢語句改為:
Select * From PHONEBOOK Where FIRSTNME = 'Steve'
就不能根據根結點和FIRSTNME = 'Steve'判斷FIRSTNME為Steve的索引項位於哪個葉結點頁上,於是只能如下圖對葉結點頁逐個掃描:
兩種方式的效率差距是顯而易見的。
匹配謂詞和篩選謂詞(Matching Predicate and Screening Predicate)
對於上述PHONEBOOK表的例子,查詢語句:
Select * From PHONEBOOK Where LASTNAME = 'Smith' and FIRSTNME = 'Steve'
中的LASTNAME = 'Smith' 和FIRSTNME = 'Steve' 就稱為匹配謂詞。
而查詢語句:
Select * From PHONEBOOK Where FIRSTNME = 'Steve'
中的FIRSTNME = 'Steve' 則稱為篩選謂詞。
一個匹配索引掃描通過匹配一系列的與選定的索引中的列相關的條件謂詞來從表中檢索資料行,對於索引中的主索引列必須至少對應一個可索引謂詞才能使用索引的樹結構進行高效查詢(否則只能對頁結點頁進行逐個掃描或者放棄索引使用表掃描)。那麼這個可索引的謂詞就稱為匹配謂詞。如果一系列的可索引謂詞都能夠匹配複合索引中從左到右連續的索引列,那麼這些可索引謂詞都是匹配謂詞。索引中其他索引列對應的出現在查詢語句中的條件謂詞就稱為篩選謂詞(對索引項進行逐個篩選)。
以上並不是匹配謂詞、篩選謂詞的標準定義,事實上這兩個概念也不好定義,舉個例子來具體說明好了。
表T1上有列C1、C2、C3、C4、C5、C6、C7、C8。其中在C1,C2,C3,C4上有索引C1234X。
A.查詢語句:Select * From T1 Where C1=5 And C2=4 And C3=7 And C4=2
該語句使用索引C1234X,匹配謂詞為C1=5、C2=4、C3=7、C4=2。使用這些謂詞可以直接完成定位,無需進行索引頁的逐個掃描。
B.查詢語句:Select * From T1 Where C2=4 And C3=7 And C4=2
該語句由於主索引列沒有相對應的謂詞,因此無法使用索引的樹結構進行查詢,只能是要麼對葉結點頁逐個掃描,要麼放棄索引進行表掃描。
如果使用索引C1234X,那麼沒有匹配謂詞,C2=4、C3=7、C4=2都是篩選謂詞。
C.查詢語句:Select * From T1 Where C1<>5 And C2=4 And C3=7
該語句由於主索引列對應非匹配謂詞,因此要麼對葉結點頁逐個掃描,要麼放棄索引使用表掃描。
如果使用索引C1234X,那麼沒有匹配謂詞,C1<>5、C2=4、C3=7都是篩選謂詞。
D.查詢語句:Select * From T1 Where C2=4 And C3=7 And C1=5
該語句使用索引C1234X,匹配謂詞為C1=5、C2=4、C3=7。注意,對應Where子句後面的謂詞,優化器會根據索引中列的順序進行重新排序(查詢重寫)。
E.查詢語句:Select * From T1 Where C1=5 And C2=4 And C4=2 And C6=10
該語句使用索引C1234X,匹配謂詞為C1=5、C2=4,篩選謂詞為C4=2,C6=10為普通謂詞(沒有索引與之對應)。可以看到,一旦謂詞對應的索引列不連續,那麼其後的索引列對應的謂詞就只能是篩選謂詞了。因為一旦不連續,那麼該謂詞就不能繼續使用樹結構進行定位了,只能對下層索引頁進行逐個掃描。
F.查詢語句:Select * From T1 Where C1=5 And C2=4 And C3>7 And C4=2
該語句使用索引C1234X,匹配謂詞為C1=5、C2=4、C3>7,篩選謂詞為C4=2。一直到C3都能夠使用樹結構進行定位,但是C4就不行了,因為C3>7給的只是一個範圍,該範圍內的下層索引頁只能由C4謂詞進行逐個掃描篩選了。
對應給定的是範圍的謂詞稱為範圍謂詞,帶between、<、>、<=、>=、like等操作符的謂詞都是範圍謂詞,一旦出現範圍謂詞(索引列對應的),匹配就停止,剩下的索引列對應的謂詞只能是篩選謂詞了。但是有一個例外,in操作符雖然也是表範圍的,但是由於它可以看作是一系列的相等匹配謂詞,單獨將其稱為In-list謂詞,它的出現不會導致匹配的終止。
由以上例子可以得出匹配謂詞的基本原則:
1.匹配謂詞必須是可索引謂詞。
2.匹配謂詞必須對應選定索引中從左到右連續的索引列,一旦出現不連續或者謂詞為範圍謂詞,匹配終止。
3.選定索引中索引列對應的非匹配謂詞仍然可以是篩選謂詞,即便該謂詞是不可索引謂詞。
例項
現在以一個更復雜的例子來說明覆合索引下的匹配索引掃描。
表T上有列C1、C2、C3、C4、C5、C6、C7、C8。其中在C1,C2,C3,C4上有索引C1234X;C5、C6上有索引C56X;C7上有唯一索引C7X。
用ACCESSTYPE表示訪問型別,ACCESEETYPE=I表示使用索引掃描,ACCESSTYPE=N表示使用帶In-list謂詞的索引掃描。ACCESSNAME表示使用的索引。MATCHCOLS表示匹配的索引列數。對照上面的規則,不再進行詳細解釋了。
Select * From T Where C1=5 And C2=7 And C3<>9
ACCESEETYPE=I , ACCESSNAME=C1234X , MATCHCOLS=2
Select * From T Where C1=5 And C2>=7 And C3=9
ACCESEETYPE=I , ACCESSNAME=C1234X , MATCHCOLS=2
Select * From T Where C1=5 And C2=7 And C5=8 And C6=13
ACCESEETYPE=I , ACCESSNAME=C56X , MATCHCOLS=2 //至於為什麼使用的是索引C56X而不是C1234X,這是由優化器的成本估算結果決定的。
Select * From T Where C1=5 And C2 in(5,6) And (C3=10 or C4=11)
ACCESEETYPE=N , ACCESSNAME=C1234X , MATCHCOLS=2 //"or"操作符連線的謂詞會被當作不可索引謂詞,因此不是匹配謂詞,但是可以作為篩選謂詞。
Select * From T Where C1=5 And C2=7 And C7=101
ACCESEETYPE=I , ACCESSNAME=C7X , MATCHCOLS=1 //通常唯一索引會優於普通索引,但也不是絕對的。
Select * From T Where C2=7 And C3=10 And C4=12 And C5=16
ACCESEETYPE=I , ACCESSNAME=C1234X , MATCHCOLS=0 //雖然C1234X上沒有匹配謂詞,C56X上有,但是優化器認為使用索引C1234X更優。
特殊謂詞(Special Predicates)
有一些特殊的謂詞,它們使用的操作符都是可索引謂詞的操作符,但是這些謂詞卻不是可索引謂詞,即不可以對該謂詞使用相應的索引。
模式匹配搜尋(Pattern Match Search)
使用“like”操作符,但是匹配的值是萬用字元前置的。比如“C1 like '%tion'“,要知道索引是按照字母從左到右排序的,萬用字元前置自然是不能使用索引進行檢索的。因此也就不是可索引謂詞了。
當然你可以使用函式得到C1值的倒序,然後使用”like 'noit%'“實現該目的。
表示式(Expressions)
考慮語句:
Select * From T Where 5*C1<=20;
雖然使用的是”<=“操作符,但是由於DB2是不會對謂詞去做代數運算的,因此”5*C1<=20“是不可索引謂詞。改寫為C1<=4就是可索引的了。
另外,不同列之間使用代數表示式同樣是不可索引的,比如”C1=C2“(C1、C2均為資料列)是不可索引謂詞。
取一次訪問(One-Fetch Access)
考慮語句:
Select min(C1) From T ;
假設在C1列上建有索引,那麼優化器會直接找到索引葉結點頁中最左側的那個索引也,從中讀出最小值即可,其他的頁直接忽視。這種沒有Where子句的SQL查詢語句由於使用了特殊的函式,同樣可以使用對應的索引。我們把這種情況稱為取一次訪問。
另外max函式自然也是能夠做取一次訪問的了。當然,使用了這樣的特殊函式且仍然帶有Where子句的,也還是屬於取一次訪問的範疇。比如:
Select max(C1) From T Where C1 Between 5 And 10;