本節書摘來自華章出版社《高并發oracle資料庫系統的架構與設計》一書中的第2章,第2.3節,作者 侯松,更多章節内容可以通路雲栖社群“華章計算機”公衆号檢視
現在,我們知道了b樹索引的結構特點,也了解到其對查詢和排序優化的意義,但是這并不代表我們就能建好用好索引了。在實際工作中,是不是還是會遇到走了索引反而查詢變慢的情況呢?雖然說不是所有的情況下索引掃描都是優于全表掃描的,但是對于一套設計成熟的系統來說,索引掃描往往是值得堅持的,應該定期進行全庫sql語句執行計劃的審查,抓出全表掃描的sql進行優化。
說一千道一萬,我們建立索引就是為了使用索引,盡可能地使查詢操作能夠走索引。但是,很遺憾,不是我們說走索引就能走索引,還是需要取決于cbo優化器的成本計算和比較情況。這其中會影響cbo優化器計算結果的因素有很多,比如:統計資訊過舊、缺少直方圖資訊、資料分布影響索引選擇度、索引聚簇因子偏差,等等。我們要用好索引,就必須要充分地了解這些特性和影響因素。
本節仍然沿襲概念結合執行個體的方式,首先,給讀者介紹索引選擇度、索引聚簇因子的概念;再輔以資料分布和資料存儲的變化對索引使用的影響;最後,再分析實際工作中的一些常見的索引被無視的情況。
在這裡,我們先抛出一個問題:什麼時候需要用索引呢?有些人會說選擇度20%以下,有些人會說10%以下,這樣的回答都不盡然,甚至可以說是不負責的。我們還是需要根據具體情況來具體分析的。
衆所周知,需要索引發揮出較高的使用效率,則在通過索引進行查詢的時候,其選擇度需要控制在一個較小的範圍内。但是,也需要考慮資料的實際分布情況。這裡我們引入兩個概念:
索引理想選擇度 = 1 / 索引列的distinct數;
索引實際選擇度 = 傳回結果集行數 / 全表行數。
通常情況下,我們所說的索引選擇度就是上面所說的實際選擇度。那麼理想選擇度是怎麼來的呢?
我們知道當一個表的num_distinct值越接近num_rows值,則優化器越傾向于走索引掃描。那麼最優情況是num_distinct=num_rows(典型代表為唯一索引,此類索引為理想狀态索引,掃描效率最高),最差情況則是num_distinct=1(不考慮空表和null值)。引進一個比例num_rows/num_distinct來表示其關聯性,該比例的值越小則越優。通過一般情況與最差情況的對比,可以得到一般情況下的選擇度,這個選擇度就是一般情況的理想選擇度。
理想選擇度=(num_rows/num_distinct)/(num_rows/1)=1/num_distinct
可以說理想選擇度反映了優化器選擇的傾向性。換而言之,如果希望優化器盡可能地選擇索引掃描,則索引設計上盡可能地參考理想選擇度的原則,它給索引設計提供一定的指導意義。
至于num_rows和num_distinct的值可以通過掃描表擷取,也可以通過如下方式查詢資料字典擷取(必須收集統計資訊):
細心的讀者讀到這裡應該已經察覺到了,我們這裡說的理想選擇度其實就是執行計劃中“集勢”(cardinality)的一個重要因子。集勢因子是cbo優化器cost成本計算的重要标準,可以說它反映了優化器的計算方式,也是決定是否走索引的關鍵因素。
索引列的集勢因子如表2-3所列:

從集勢因子來看,不難看出“<>”和“not in”的情況比較難以高效使用索引。而對“=”,“<、>、<=、>=”和“in”的情況,基本上都可以由1/num_distinct決定,也可以說它們最小公約數單元就是等值查詢。這個因子,也就是我們所說的理想選擇度,基本上可以反映索引列各種高效查詢的優化器成本計算情況。
1.?均勻分布的情況
當資料分布是完全均勻的,則會發現理想選擇度和實際選擇度是相等的,也就是說理想選擇度是一種完全理想化的資料分布狀态。當cbo優化器在計算索引掃描成本的時候,如果缺少索引列直方圖資訊,則會認為資料是完全均勻分布的。這個時候無論col的取值是多少,其選擇度都是一樣的,即理想選擇度等于實際選擇度。此時成本的比較上,通過索引掃描再回表取數要遠小于全表掃描,如圖2-8所示。
然而,這種情況基本上是不存在的。如果索引列上的資料分布較為均勻,那麼與cbo優化器計算的結果偏差就不會太大,反之,則會導緻執行計劃跑偏。是以,索引設計的另一原則就是“盡可能地保證索引列資料分布均勻一些”。
說到資料的分布均勻程度會影響索引的效率,先來使用理想選擇度和實際選擇度來考察一個均勻分布的例子吧。具體步驟和sql語句如下所示:
步驟1 建立一下相關的表和索引:
步驟2 初始化資料,順序均勻地插入10萬行資料,col1列num_distinct值控制為10:
步驟3 收集一下表和索引的統計資訊,設定method_opt參數為'for all columns size 1',先不收集直方圖資訊,看看資料分布對索引選擇的影響。
此時,可以看到索引列col1上的資料分布是完全均勻的。是以,不論是col1=1,還是col1=5的情況,都是能夠很好地利用索引掃描的。理想選擇度和實際選擇度均為10%,即優化器計算的選擇度和實際情況是完全相符的。示例如下所示:
2.?非均勻分布的情況
如果說在索引列上的資料分布不是均勻的呢?如圖2-9所示,來看一個比較極端的例子。col=2的行數占總行數的60%,那麼查詢col=2的時候,實際選擇度則為60%,然而col為其他值的實際選擇度僅為10%。如果按照實際選擇度來走的話,col=2走全表掃描,其他情況走索引掃描是一個比較理想的選擇。
但是,優化器的實際處理情況未必如此。這個時候,如果我們沒有col列上的直方圖,優化器會認為資料是均勻分布的,則理想選擇度 = 1/num_distinct = 20%,很有可能都走了全表掃描。這對于col不為2的情況幾乎是不能接受的。
這種情況相信在很多應用中都是存在的,隻是有可能不會表現得這麼極端而已。直方圖的收集對于大表來說,是不可想象的,因為收集一次開銷太大,對高并發的oltp系統幾乎是不可能完成的任務。那如何去解決這個問題呢?這又将說回到索引設計的話題上來。對于這種資料分布極度傾斜的情況就不應該建索引,如果不得不建的話,盡可能收集直方圖。
回到前面的例子,接下來我們人為來制造一些麻煩吧,打亂原有的均勻分布。如下例所示,可以看到,col1=5的記錄行已經占了全表記錄總數的50%,col1索引列已經嚴重傾斜。但是,抛開col1=5的情況,其他幾種情況,都還是有比較好的選擇度的。
表經過了大批量的dml操作,統計資訊已經過舊了。如果仍采用舊的統計資訊,上面基于col1的查詢,仍然都将繼續索引掃描的方式,這對于col1=5來說,就不是最優的了。
此時,需要重新收集一次表和索引的統計資訊,仍然選擇不收集直方圖。因為沒有直方圖資訊,優化器将無視資料分布的傾斜。下面的例子中,col1=1和col1=5的情況,都走了全表掃描,顯然這個結果也是不能讓人滿意的。
利用理想選擇度和實際選擇度來分析一下吧。資料分布傾斜後,col1=5的實際選擇度變為50%,其他情況仍為10%。但是沒有直方圖資訊,優化器意識不到這一點,它會認為理想選擇度是從10%變為了16.7%,都應該走全表掃描了。
換個角度來思考一下,如果我們沒有idx_alex_t03_col1這個索引,情況會如何呢?當然也将是全部走全表掃描的。那不得不反問一句,idx_alex_t03_col1這個索引還有存在的意義嗎?
要讓idx_alex_t03_col1索引有存在的意義,就需要依賴于col1列上的直方圖資訊收集。我們重新收集一下統計資訊和直方圖吧,示例如下所示:
再來對比一下col1=1和col1=5查詢的執行計劃看看,我們神奇地發現了兩種截然不同的情況,而且都是最優的。
說到這裡,有人可能會提出質疑:“oracle 11g提供的自适應遊标共享(acs)不是就可以根據不同的綁定變量生成不同的執行計劃嗎?”這真的是一個不錯的主意,但也僅僅是不錯而已。
我們不要忘了使用綁定變量的時候,oracle有一個綁定變量窺探的機制,sql語句第一次執行決定了以後同樣的sql語句的執行計劃。如果在缺失直方圖資訊的情況下,其結果和不綁定變量的情況是一樣的。如果很幸運地擁有直方圖資訊呢?我們第一次執行的col1=:vid綁定變量:vid:=1,則會走索引掃描,第二次:vid:=5也将繼續索引掃描。反過來的話,先執行:vid:=5,再執行:vid:=1,則都會走全表掃描。這對我們來說是沒有什麼幫助的。即使oracle 11g通過自适應遊标共享進行了優化,但對資料分布傾斜也将是力不從心的。
細心的讀者可能已經注意到了,上面我們說的兩個例子,是很極端化的例子,一個過分均勻,一個過分傾斜,在實際應用中,我們還是需要中庸一點的。在索引設計和使用的時候,需要關注以下幾點:
需要像優化器一樣去思考,盡可能地參考理想選擇度的原則;
盡可能保證索引列資料分布均勻,否則不要建索引;
如果不得不對資料分布嚴重傾斜的列建索引,請收集直方圖資訊,同時關注綁定變量窺探的影響。
再次回到上一節抛出的問題,什麼時候應該用索引?前面我們分析過了索引選擇度和資料分布的問題,而另一個會影響索引使用的關鍵因素就是索引聚簇因子(index clustering factor)。
什麼是索引聚簇因子呢?索引聚簇因子是指按照索引列值進行了排序的索引條目順序和其對應表中資料行順序的相似程度。比較理想的狀況就好比一對雙胞胎,其相似程度是非常大的,此時索引使用是非常高效的。在oracle中,聚簇因子大小對資料讀取效率有着直接的影響,聚簇因子值越小,則說明相似程度越大,索引使用将越趨于高效。
聚簇因子是如何影響索引的使用性能的呢?主要從i/o開銷這個角度來思考。如圖2-10所示,我們先來對比一下左右兩種情況的聚簇因子。我們假設一個表中隻有三個資料塊(data block),每個資料塊隻能存儲三行資料,共需存儲9行記錄。現有一個索引列,9行記錄對應索引列值為123123123,在索引結構中對鍵值是有序排列的,那索引條目存儲的順序應該為111222333。右圖中,表中資料存儲的順序也是111222333,和索引順序是一緻的;左圖中表和索引存儲的結構則是大相徑庭的。按照聚簇因子的定義,左圖可以視為較差(或者較大)的聚簇因子,右圖可以視為較好(或者較小)的聚簇因子。
當進行索引掃描的時候,其實左右圖并無什麼差別,因為索引都是有序的,但是在回表取數的時候,右圖的i/o開銷明顯小于左圖的。現在假設每次i/o隻能讀取一個資料塊,那麼當查詢col=1的時候,右圖隻需一次i/o,左圖需要三次,i/o上的優勢立現。優化器在cost計算的時候,對于左圖的情況甚至會選擇全表掃描,而放棄走索引。
為什麼會造成表存儲結構和索引存儲結構不一緻呢?索引結構的存儲已經是有序排序了,是以不一緻的問題出在表的存儲上。我們通常所說的表都是堆表,其最大特征就是資料存儲的獨立性,資料的存儲和數值本身沒有任何關系,是随機存儲在任意位置上的,即随機存儲在任意的資料塊上。
很幸運的是,oracle提供了索引的聚簇因子,可以通過資料字典查詢到相關索引的聚簇因子資訊,如下:
簡單來說,clustering_factor反映的是通過索引掃描通路一張表,需要通路的表的資料塊數量,即反映i/o的次數。這個clustering_factor是如何計算出來的呢?
1)掃描索引結構;
2)順序對比相鄰索引條目的rowid,如果兩個rowid屬于不同資料塊,那麼clustering_factor增加1;
3)整個索引掃描結束後,就可以得到該索引的聚簇因子數值。
了解了clustering_factor的計算方法,我們可以得出以下兩個極端的情況,即聚簇因子最大和最小的情況:
clustering_factor最小時,其無限接近于表的資料塊數,該表是按照索引字段順序存儲的;
clustering_factor最大時,其無限接近于表的行數,該表是完全不按照索引字段順序存儲的。
結合聚簇因子和選擇度,基本上就可以确定索引掃描的cost開銷了。
1.?聚簇因子較好的情況
接下來通過一個執行個體來驗證一下聚簇因子對索引性能的影響吧。先考察聚簇因子較好的情況,此時clustering_factor的數值将會比較小。下面例子中,我們按照前面提到的“111222333”的方式進行資料入庫。
步驟1 清空表alex_t03的資料:
sql> truncate table alex_t03;
步驟2 按照“11122233”的方式重新插入10萬行資料,num_distinct值控制為200:
步驟3 重新收集一下表和索引的統計資訊,這裡不關注直方圖資訊:
主鍵列的資料入庫是完全有序的,可以将主鍵索引視為一個理想的聚簇因子情況,将col1列的索引聚簇因子與之對比一下,可以發現clustering_factor數值上是差不多的,索引idx_alex_t03_col1的聚簇因子比較好,遠小于資料行數,接近資料塊數。統計結果如下所示:
當進行col1索引列的查詢的時候,毋庸置疑的是進行索引掃描了,而且cost開銷相對較小,也就是說索引利用比較高效。示例如下所示:
2.?聚簇因子較差的情況
如果按照“123123123”的方式進行資料入庫是不是會出現另一個極端的情況呢?同樣通過一個例子來看一下吧,仍然使用alex_t03表,僅僅改變資料入庫順序。
步驟1 清空alex_t03的資料:
步驟2 按照“123123123”的方式重新插入10萬行資料,num_distinct值控制為200:
如預料的一樣,clustering_factor變得很大,遠遠大于資料塊數,更趨于接近資料行數,顯示這是一個比較差的聚簇因子的情況。統計結果如下所示:
再進行一次同樣的查詢操作,發現優化器放棄了索引掃描而進行了全表掃描,這意味着此時全表掃描的開銷更小。從下例的統計資訊看到,全表掃描的實體讀和邏輯讀都比較好聚簇因子的情況要大得多,甚至出現了16次額外的記憶體排序操作。
即便如此,優化器仍認為全表掃描更優,那強制走一下索引掃描看看情況如何呢?如下例所示,比較索引掃描和全表掃描的統計資訊似乎相差無幾,但是cost開銷、索引掃描大了很多。
此時,如果再對比聚簇因子較好和較差兩種情況下的索引掃描情況,很容易就驗證了我們之前的說法,較好的聚簇因子會帶來較大的i/o優勢。
在實際應用中,表中資料的入庫有一定的随機性,其順序是我們無法控制的,這意味着索引的聚簇因子也很難得到控制。這對我們在索引設計上也是一個較大的挑戰,在建立索引之前,應該盡可能地了解業務資料的存儲特性,保證資料存儲順序有一定的規律,即擁有較小的聚簇因子,索引才能高效使用。如果不能保證較小聚簇因子,要想通過後期的維護來修正,那基本上是不可能實作的。
綜合以上内容,我們可以來總結一下了,一個設計優秀的索引應該具有以下特點:
具有較好的選擇度,能參考理想選擇度來界定;
索引列的資料分布足夠趨于均勻化;
具有較小的聚簇因子。
當不知道如何把握的時候,可以參考一下唯一索引,其從各方面來思考都是最高效的,盡可能地使你的索引接近于它。
1.?複合索引設計
在工作中,我們時常會被問及一個問題:“我将如何選擇索引列來建立複合索引呢?”舉一個例子來說說看吧。
現在有一張表的三個列:a、b、c,在日常的業務應用中,會用到兩兩組合的查詢,即:a and b,b and c,a and c,将如何建複合索引呢?這是一個很不明确的需求,我們很難以此為據來作出判斷,需要進一步跟需求方溝通。
經過資料量和資料分布等情況的分析,确定是需要建索引的,問題将集中在如何去建,建什麼樣的索引。
架構師:“這三種場景發生的機率大緻如何呢?”
開發者:“各占三分之一吧。”
架構師:“除此之外,還有這三個列上其他查詢嗎?”
開發者:“可能還有少量的b列和c列的單列查詢吧,但是真的比較少。”
架構師:“那這三個列的資料區分度是怎麼樣的呢?”
開發者:“a列區分度比較低,b列和c列将比較高。”
架構師:“這真的是一個比較棘手的問題。……問題主要集中在這三個列的區分度上,如果a列很低,b和c很高的話,我建議可以考慮不建複合索引,隻建b列和c列的單列索引。”
開發者:“這是你的第一個建議嗎?但是我并不是很确定a列的區分度是否真的像預期的那麼小,或者說b列和c列的區分度未必像預期的那麼大。”
架構師:“是的,如果用單列索引就能解決問題,當然是最好不過的了。但是,從你的描述中,我對使用單列索引還是有所擔心的,我建議可以考慮建(b,c)複合索引和c列單列索引。這樣,(b,c)複合索引可以覆寫b and c查詢和a and b查詢,c列單列索引可以覆寫a and c查詢,因為a列區分度不高,可以不考慮其走索引。”
開發者:“那為什麼不幹脆建(b,c),(b,a),(c,a)三個複合索引呢?”
架構師:“這個當然很好了,但是索引維護開銷太大,未必是好事。”
開發者:“那能不能使用index skip scan的特性呢?”
架構師:“非必要時不要用,盡可能選擇區分度比較高的列作為複合索引的前導列,這樣前導列單列查詢的時候也能很好地使用複合索引。”
開發者:“那能不能建三個列的複合索引呢?”
架構師:“能是能,但是不建議這麼幹。你這個表資料量比較大的話,你可以相像一下這個索引結構會多複雜,後期維護也是很痛苦的。”
架構師:“好了,我們現在一共有三個方案。第一,b列和c列的單列索引;第二,(b,c)複合索引和c列單列索引;第三,(b,c),(b,a),(c,a)三個複合索引。其中,第二個是最優推薦的。”
開發者:“好的,那就按照第二個來建吧。”
架構師:“還不行。我們需要請開發dba做一次影響分析後,再确定是否可以建。”
開發者:“影響分析?怎麼做的呢?”
架構師:“就是對比索引建立前後該表上所有sql語句的執行計劃的變化情況。如果變好了,自然沒有問題,如果變差了,就不能建立了。如果必須建立,就需要使用outline或者spm固定有可能變差的執行計劃後,再行建立。”
開發者:“那不是很麻煩嗎?不這麼幹行不行呢?”
架構師:“是很麻煩,但是為了保證系統的穩定運作,這是必不可少的。甯願把難度做在設計階段,也不要把難度留給運維階段。”
通過上述的一段工作對話,我們大緻可以了解到一些複合索引設計和使用的小技巧了吧。其實,上面提到的影響分析,不隻是在建複合索引的時候需要做,在建單列索引和收集統計資訊等有可能造成執行計劃變化的dba操作都需要做。
2.?使用執行個體
複合索引的設計很大程度上可以參考單列索引來進行,其比較大的一個特點就是前導列和後置列的選擇問題。通過下面一個例子,我們來對比看一下吧。具體步驟和sql語句如下所示:
步驟2 初始化資料,制造a列超低區分度,b、c、d三列較高區分度:
步驟3 同樣收集一下表和索引的統計資訊:
對于查詢條件覆寫了所有複合索引列,不論是低區分度的前導列還是高區分度的前導列,同樣走了index range scan,達到較好的預期效果。示例如下所示:
在複合索引的使用中,查詢條件覆寫所有複合索引列的情況是最優的。如果在建索引的時候,能夠充分考慮到這一點自然是最好的。就像前一節的場景對話,如果能建立(b,c),(b,a),(c,a)三個複合索引,完全覆寫查詢場景自然是最優的選擇,但是也不得不考慮其運維代價。說白了,就是要用更少的、結構更簡單的索引來達成更多的場景需求,實作索引的高效使用。
對于複合索引來說,其高效在哪裡呢?索引列全覆寫自然不用說,無論如何都是高效的。問題應該集中在前導列和後置列的使用上。衆所周知,複合索引的前導列是可以覆寫其單列查詢的,而後置列則未必,除非滿足index skip scan的條件。如下面的例子所示。
對于較低區分度前導列的複合索引idx_alex_t04_ab來說,當發生前導列單列查詢是無法使用到索引的,或者說不使用索引效率更高。
在後置列查詢中,我們看到index skip scan的效率還是挺高的。那是因為我們選擇的前導列a有極低的區分度,否則的話,其效率不會太高,或者不使用索引掃描而選擇全表掃描。
可以這麼說,一個前導列區分度不高的複合索引,滿足不了前導列單列查詢的需要,也未必能較好地滿足後置列的單列查詢需要。這樣的複合索引的使用效率就顯得不高了。
反觀前導列區分度較高的複合索引idx_alex_t04_cd,前導列的單列查詢毋庸置疑地滿足了高效索引掃描。如下所示:
對于後置列的單列查詢來說,就直接說“不”,簡單幹脆,便于把握,避免了“未必”這種模棱兩可、難以把握的情況,也減少了後期出現問題和偏差的幾率。如下所示:
小結一下複合索引的設計和使用吧:
在複合索引的應用中,查詢條件覆寫所有的索引列,查詢效果最優;
盡可能地用更少的、結構更簡單的索引來達成更多的場景需求;
一般來說,在複合索引建立的時候,前導列都建議選擇區分度較高的,故index skip scan往往就是被優化對象。
說一千道一萬,索引建立了就是要用的,可偏偏很多時候,索引被sql語句無視了,沒有被用上,此時往往需要dba的介入進行優化。抛開索引本身的問題不說,哪些情況下索引會被無視呢?下面我們展開幾個比較典型的場景來讨論一下吧。準備工作具體步驟如下:
步驟2 收集一下表和索引的統計資訊:
1.?列與列的對比
當進行單表查詢的時候,發生列和列的對比是無法走索引的,即使對比的兩個列上都有索引。這裡,我們也可以想象一下,如果需要它走索引,将會是怎麼樣的呢?pk_alex_t02和idx_alex_t02_objid兩個索引進行聯立對比,篩選出等值的情況,這樣的做法遠不如進行全表掃描來得高效了。示例如下所示:
null值一直是一個很難搞的東西,在查詢、排序等操作時經常制造麻煩。在表的設計當中,我們就應該盡可能避免null的出現,賦予一些沒有實際意義的預設值來取代null值。在索引建立的時候,我們很難去給null建立合适的條目,進行null值查詢的時候,也将不大可能進行索引掃描。也就是說一個表的列值存在null值時,該列的索引是不會為null值建立條目的,那麼索引的值是少于表的值的,null值的查詢過程自然就忽略了索引。如下所示:
我們知道索引會給每個索引列的值對應一個索引條目,當告訴索引選擇出某個值或某個範圍的值時,索引就會對應到相應的索引條目。反過來看,當告訴索引不要選擇某個值或某個範圍的值,索引就很難對應相應條目了。
下面的例子中,<>、not in、not exists的情況都是很難使用到索引的:
4.?like前置通配符
當使用like進行模糊查詢的時候,我們一般推薦使用後置的通配符,這樣可以較好地利用索引掃描,較為高效。示例如下所示:
| 0 | select statement | | 2 | 198 | 3 (0)|
| 1 | table access by index rowid| alex_t02 | 2 | 198 | 3 (0)|
但是實際使用中,很多時候是我們不得不使用前置通配符,這樣的操作是無法使用索引的。為什麼呢?我們試想一下,如果進行索引掃描的話,索引結構是有序的,模糊的前置很可能要掃描絕大部分或全部的索引塊,再回表取數時,也很有可能掃描絕大部分的資料塊,這樣的cost開銷是非常大的,優化器甯願選擇直接進行全表掃描,實際cost開銷會更節省一些。是以,前置通配符的模糊查詢是不能走索引的。
業務系統設計的時候,盡可能地考慮到模糊查詢,避免使用低效的前置通配符,而更多地使用能走索引的較高效的後置通配符。
5.?條件列上使用函數
在下面的例子中,在索引列上使用了函數,這同樣是無法使用索引的。在實際應用中,盡可能地使用第二種方式,在變量上使用函數轉換後,再與索引列進行對比。當不得不在索引列上使用函數的時候,就必須在該列上建立函數索引。但是,函數索引不是一個很高效的東西,應盡量避免使用或者少用。示例如下所示:
說到此處,資料類型隐式轉換的問題是不得不提的。隐式轉換實質上也是一種函數轉換的操作,隻不過是沒有明确寫明函數,由oracle自動完成的。如下面的例子,id列是number型的,如果查詢id='12345',oracle會自動轉換為id=12345後,再進行查詢,轉換的過程實質上就是做了一次to_number函數的轉換操作。這樣同樣是無法進行索引掃描的。sql語句如下:
sql> select * from alex_t02 where id = '12345';
sql> select * from alex_t02 where id = to_number('12345');
在實際應用中,資料類型隐式轉換是需要盡量避免的,隐式轉換不但不能進行索引掃描,而且會影響綁定變量的使用。
6.?高區分度前導列的複合索引後置列查詢
高區分度前導列的複合索引無法用于後置列查詢,這個例子其實前面的章節已經讨論過了。如果前導列區分度很低,可以走index skip scan,如果前導列區分度高的話,進行index skip scan時分裂邏輯子索引開銷将非常大,不如直接走全表掃描。示例如下: