上次丁俊大師在社羣上作了CBO優化器和坑爹案例的分享後,反響不是通常的強烈,但其中也有一部分同窗表示過高大上了(我也是這樣以爲的),消化起來至關有難度,因而便有了本文。繞開復雜的CBO優化器不說,本文將幫你理清那些由於SQL語句編寫規範問題致使沒有充分利用索引來大幅提高效率的使用場景。html
1、SQL沒法走索引的狀況及解決思路linux
由於數據庫優化器不夠智能,或者一些邏輯緣由,致使SQL在比較適合走索引的狀況下卻沒法正確利用索引。這時候,除了給數據庫須要的統計信息以外,SQL語句自己還必需要給優化器足夠多的額外有效信息,幫助優化器可以選擇更好的執行計劃。要讓優化器正確選擇須要的索引,要考慮兩點:sql
說明:這裏說的走不了索引,是指走不了正常的RANGE SCAN,非(FAST) FULL INDEX SCAN。數據庫
SQL沒法走索引常見的有以下8種狀況:運維
第1、二種狀況在現實中比較常見,解決辦法也相對比較簡單,下面就再也不做詳細展開了。ide
謂詞使用了不等於(<>,!=),走不了索引函數
解決方法:工具
舉個例子,先構建測試場景:性能
謂詞使用<>,沒法利用索引:測試
將<>改寫爲OR鏈接後,可以正確使用索引,走OR擴展:
若是業務容許,改寫爲下列語句也是走索引的,再也不演示。
SELECT * FROM t WHERE t.NAME IN (‘ORADB1′,’ORADB2′,’ORADB3’);
LIKE前通配或全通配的查詢,走不了索引
解決方法,有以下三種:
(1)根據業務需求,是否能夠把前通配去掉
原來全通配,沒法走索引:
把前通配去掉,改成後通配,能夠正常使用索引:
(2)和此LIKE同樣的前通配或全通配的SQL有不少,此謂詞的LIKE變化不大?若是是,考慮創建函數索引,不然對於全通配問題最好辦法就是全文索引。
建立instr函數索引:
(3)若是隻是前通配,可使用reverse函數索引(不是翻轉鍵索引)
原始語句:
SELECT * FROM t WHERE t.NAME LIKE ‘%ORADB1’;
建立reverse函數索引,並改寫語句,注意查找值要倒序:
注意:若是通配查詢的是中文,要注意使用REVERSE翻轉條件值,由於REVERSE內部會按字節翻轉的,正確寫法如:
SELECT * FROM t WHERE REVERSE(t.name) LIKE REVERSE(‘數據’)||’%’;
不然查詢出來的數據不對,將可能影響到業務的正常運行。
索引列使用了函數、數學運算、其餘表達式等,走不了索引
解決方法:去掉對索引列的相關運算,保持索引列純淨。
目前優化器對一些數學運算,還沒法作很好的消除動做,因此對於索引列應該儘可能保持純淨,不然可能沒法用上正確的索引。
舉例:
把語句的條件改寫一下,將運算去掉:
以上例子只是簡單的數學運算,可能的運算還有和其餘列運算,好比where ID+ext_col…
記住一個原則:儘可能保持索引列純淨。
使用了隱式類型轉換,走不了索引
解決方法:必須避免隱式類型轉換,所有要求顯式類型轉換(非索引列),且避免對索引列進行類型轉換(有函數索引除外)。若是類型不一致,無論是否發生自動類型轉換,謂詞的右值應該顯式轉換爲與索引列保持一致(對於非索引列的運算也應該如此)。
舉例:
從以上兩次查詢對比來看,第一次查詢發生了類型轉換,能夠經過執行計劃中的謂詞信息獲知。經過分析發現,X由於是VARCHAR2,優先級比數值類型低,遇到數值類型,會TO_NUMBER隱式轉換,因此索引失效。第二次查詢,經過傳入與索引列類型一致的字符串後,得以解決。
查詢轉換失敗,走不了索引
查詢轉換是很是複雜的過程,ORACLE CBO的查詢轉換有好幾十種,好比CVM :complex view merging ,SU:subquery unnest, JPPD:JOIN PREDICATE PUSH DOWN等(在10053文件裏均可以看到)。若是查詢轉換失敗,那麼必將影響後續優化器的一些操做,好比JPPD中JOIN謂詞沒法推入到視圖中,那麼極可能視圖就沒法走索引了。並且,查詢轉換有不少BUG,觸發BUG須要找到緣由,好比設置隱含參數、fix control等,或者改寫SQL繞過BUG。以下例所示:
其中AB_XRTOFFREC_201703是UNION ALL查詢組成的視圖,這個查詢在10.2.0.4上很正常,升級到11.2.0.4後執行計劃顯示不走索引,性能很是差。
在10g中的執行計劃:
在11g中的錯誤執行計劃:
經過收集統計信息都無效,將優化器降級到10.2.0.4即有效。很顯然,這是引入了BUG或者新的限制。一旦遇到這種是BUG或限制致使的,能夠經過10053跟蹤文件或者SQLT來進行分析。對於這條語句沒法走JPPD查詢轉換,在10053中就能夠找到緣由:
而後在MOS中查看得知是BUG:9380298,默認開關關閉。
ORACLE針對這樣的查詢,爲了防止遇到笛卡爾積,默認把修復BUG的補丁關閉了。顯然經過設置_fix_control參數打開9380298 fix便可。
語句邏輯問題,致使優化器選擇不了索引
舉一個典型的例子,先準備測試表,並在其上建立一個組合索引:
查詢需求:查找建立時間是2013年的,而且最後ddl時間比建立時間大1天以上的對象。
這個索引是組合索引,上面的語句對前導列進行了運行,也不符合走index skip scan的條件,因此,走FULL TABLE SCAN。那麼是否能夠經過邏輯改寫走索引呢,基於保持索引列純淨的原則,將create_date移到右邊,語句以下:
改寫後發現,仍是沒有走索引,由於Oracle認爲前導列右邊的created不固定,沒法從指定索引處查找。經過分析得知,Oracle謂詞傳遞有必定限制,create_date+1沒法作謂詞傳遞給last_ddl_time。再次改寫:
此時Oracle知道將謂詞傳遞給last_ddl_time了,T.LAST_DDL_TIME>=TO_DATE(‘ 2013-01-01 00:00:00’, ‘syyyy-mm-dd hh24:mi:ss’)。固然,也能夠手動謂詞傳遞,last_ddl_time確定大於等於DATE’2013-1-2′:
還未完,咱們繼續往下看:
若是查詢條件中無t.created>=DATE’2013-1-1’,即以下面語句:
–由此兩數據比較可知,應該走索引更佳。由於沒有其餘過濾條件,能夠考慮創建函數索引:
SQL> CREATE INDEX idx1_t_object ON t_objects(last_ddl_time-created);
–注意收集直方圖,由於分佈不均
SQL> exec dbms_stats.gather_table_stats(ownname => USER,tabname => ‘t_objects’,estimate_percent => 100,method_opt => ‘for all indexed columns’,cascade => TRUE);
固然,對於兩個都是範圍的查詢,這裏只能經過一個列來輪詢索引,先作access,再作filter。
SQL語句的邏輯改寫很重要,每每經過邏輯改寫就能改變SQL的執行計劃,從很差的計劃到好的計劃,好比semi join,anti join與or,每每走FILTER致使執行計劃較差,這時候就須要經過邏輯等價改寫。邏輯等價改寫每每須要掌握一些集合的知識,好比NOT (A AND B)==NOT A OR NOT B,NOT (A OR B)==NOT A AND NOT B等。
總結
SQL有索引而不走索引的狀況還有不少,好比在DBLINK查詢中,可能走不了索引,這時候須要經過driving_site hint或者遠程庫創建視圖等方式解決等,須要綜合從語法語義、索引選擇性、索引訪問特色等多方面進行分析。
2、如何將SQL開發規範落地
上面說到的問題,說到底都是不遵照數據庫開發規範的問題。說到數據庫開發規範,估計不少企業都有制定對應的規範及要求,但說到落地執行狀況,這個就比較困難了。若是企業在乎旨上是指望開發人員去學懂規範,而後學以至用,就有點太理想化了。因而,爲了保證開發人員真的是按照數據庫開發規範來編寫代碼,不少企業就在應用上線前增長了一道SQL上線審覈的工序。
說到SQL上線審覈,關鍵要解決三個問題:
一、如何在上線的應用版本中發現新增的SQL語句;
二、新增SQL存在哪些問題,如何快速準確的定位;
三、對於問題SQL,如何快速提供優化方案。
這三個問題,是一環扣一環的,解決不了前面的問題,就無從解決後面的問題。然而,應用系統SQL衆多,若是單靠人工,難度是很大的,專家資源投入就更不說了,顯然不能知足當今IT系統高速發展的須要。
這裏跟你們分享咱們在這方面的一些實踐和成果。經過結合多年的運維和優化經驗,咱們自主研發了SQL審覈工具,不只能夠自動化完成SQL上線審覈,還能夠作到SQL的性能監控和自動優化,達到SQL全生命週期管理的效果。對於SQL上線審覈,咱們將開發規範規則化後落到SQL審覈平臺,內置了4個維度、200多種常見的審查規則,還支持靈活的按需添加規則。同時,審查的不僅是SQL語句自己,還包括了對錶的模型設計、索引的構建。
在應用新版本上線前,經過SQL審覈平臺,自動分析出版本的新增SQL,基於以上規則對新增SQL進行審查,並自動提供優化建議,可生成可視化的報表和詳細報告。無論是DBA仍是開發人員均可以基於此平臺,對問題進行確認和解決,實現系統優化前移、提高應用版本質量的目標。
3、總結
本文主要和你們分享了SQL沒法走索引的一些常見情景及解決方法,固然,SQL的規範化使用是十分重要的,SQL的優化也不只僅侷限於索引的優化。因此,只有平時多積累,結合理論多實踐,遇到問題時才能指揮若定,對症下藥、藥到病除。另外,企業在IT建設中要重視開發規範的落地執行,必要時使用合適的工具,在加速IT環境建設效率的同時,還能兼顧到IT系統的建設質量,作到兩不誤。