高級SQL優化(二)

充分利用索引
索引的限制
1. 索引對不等號和NOT的限制
  如果WHERE條件中出現!=或者<>,即使該列建立了索引,則該索引也不會被使用;如果不恰當的使用了NOT,則索引也不會被使用。
Oracle 10g起,在基於CBO的優化器模式下Oralce會進行自動優化,但在基於RBO(基於規則)的優化器模式下,依然保持此規則。
  
 
1. 索引對不等號和NOT的限制
   RBO模式下,執行計劃如下:
   
1. 索引對不等號和NOT的限制
   RBO模式下,執行情況如下:
  
 
  此時使用變通寫法的耗費爲:0.407/2.187=1.60%!
1. 索引對不等號和NOT的限制
   CBO模式下,執行情況如下:
 
 
此時使用變通寫法的耗費節約不到0.03秒,但依然更優,故此推薦此種變通寫法,再看此時使用NOT:
1. 索引對不等號和NOT的限制
   CBO模式下,在JYJE列的索引上使用NOT:
 
爲使用<>的:0.156/0.329=47.42%!爲變通寫法的使用0.156/0.297=52.53%!  此這種寫法最優!
 
1. 索引對不等號和NOT的限制
   一般,WHERE條件中,如果索引列是字符列,使用NOT往往也不會使用索引:
 
結論:如果索引列是數字,則對於不等號的處理可以變更爲NOT的方式或者(大於 OR 小於)的方式① ;對於確實無法不使用不等號的方式,可以使用默認值② ;如果可以建立位圖索引則使用位圖索引③ ;否則可以考慮使用分區等方法進行優化④ ,具體是情況而定。
2. 索引對IS NULL的限制
   一般來說,如果WHERE子句基於的列是可空的列,且其建立了索引,如果使用了IS NULL,由於NULL的列本身不包含在索引中,因此無法利用索引。
所以一般對要建立索引的列不要設置爲可空,如果確實含有空值,建議使用默認值代替空值,具體參見前面章節“SQL優化技巧”部分的“使用默認值”。
 
3. 索引對函數的限制
基於索引IDX_BIGTAB_OBJECTNAME,執行情況如下:
 
 
執行計劃情況如下:
 
這是因爲該索引是常規b-tree索引,對該列在WHERE子句中使用了函數,則不能使用索引。因此,對在WHERE子句中經常要使用函數時,應該建立基於函數的索引,且 只有當查詢語句包含該函數或者表達式時,基於函數的索引纔會被調 。詳情請參見索引部分的理論講解!
 
創建並使用函數索引:
 
  
創建並使用函數索引:
此時使用基於函數的索引效率是原來的2.782/0.188=14.78!唄!
4. 索引對不匹配數據類型的限制
先看執行情況:
 
不匹配的類型執行的時間是匹配的類型的 2.187/0.266=8.2 倍!
 
再看執行計劃:
 
原因分析:
  因爲ACCOUNT_TRADE表的字段YKKH是CHAR,因此在對其指定的值是數字時,Oracle雖然能隱式的執行數字和字符的轉換,但不會調用其索引。而當對其指定是字符時,則不存在此問題,索引可以調用。
注意:因爲數據類型的不匹配和Oracle對數據類型的隱式轉換,此種類型的低效代碼在任何項目中均可能因爲大意而存在,因此建議開發人員和管理人員要定期抽查相應的代碼,以杜絕此類低效代碼!
索引類型總結
類型
,描述
b-tree索引
最常最多使用的索引,其樹結構與二叉樹比較類似,根據ROWID快速定位所訪問的行
bitmap索引
使用位圖來管理與數據行的對應關係,適用於基數比較少的列
降序索引
降序索引在葉子節點中的存儲從左到右是按照從大到小排序的;一般是針對逆向排序較多的查詢時才使用該類型索引
函數索引
針對要頻繁對列使用函數的索引,只有當查詢語句包含該函數或者表達式時,基於函數的索引纔會被調用
反轉索引
反轉了b*tree索引碼中的字節,使索引條目分配更均勻,多用於並行服務器環境下,用於減少索引的競爭
分區索引
分區表的索引,又包括本地分區索引(本地前綴分區索引和本地非前綴分區索引)和全局索引,一般建議使用本地分區索引,因其與基表具有良好的數據均衡性和可維護性
 
 
訪問路徑
1. 全表掃描
 全表掃描(FULL TABLE SCANS)時所有行、所有數據塊均會被讀到,是 效率最 的一種,一般會在表 缺少索引 讀取大量數據 訪問小表 高併發時發生。
 
 
2. ROWID掃描
  ROWID掃描(ROWID SCANS)是通過ROWID中數據文件和塊位置訪問數據行。一般作爲訪問索引後的第二步,如果訪問的列全部包含在索引中,則不會執行ROWID掃描。
 
  作爲索引訪問後的第二步:
  訪問的列全部在索引中不再執行ROWID掃描 
 
3. 索引掃描
  索引掃描(INDEX SCANS)包含全索引掃描(full index scan、FIS)、快速全索引掃描(fast full index scan、FFIS)、索引範圍掃描(index range scan)、索引唯一掃描 (index unique scan)、索引跳躍式掃描 (index skip scan)、位圖索引掃描(bitmap index scan), 其中前5種在本系列課程的索引章 節部分已經講解了其理論和示例。位圖索引示例如下:
 
3. 索引掃描
類型
方式
發生條件
 1.FULL INDEX SCANS
逐一讀取索引中的所有塊,由於索引中數據已按索引鍵排序,因此會忽略掉排序
1.ORDER BY中的列全部在該索引中時 
2.ORDER BY中列的順序滿足索引中前導列的順序時 
3.使用GROUP BY且該子句中的列在索引中時
2.FAST FULL INDEX SCANS
只掃描索引中的數據,不會掃描表中的數據;由於索引中數據未按索引鍵排序,因此不能忽略掉排序
當同時滿足下列條件是,Oracle用FFIS替代FIS: 
1.查詢的所有列均包含在索引中 
2.索引中的列至少一個具有not null約束
3.INDEX RANGE SCANS
訪問選擇性數據最常用的掃描方式;按順序的對某個索引進行掃描,返回數據是升序排列的,可以使用唯一索引和非唯一索引;如果對索引列使用ORDER BY/GROUP BY則可省略排序
1.在唯一索引上使用範圍操作符(>、<、>=、<=、<>、BETWEEN) 
2.在組合索引上使用部分列進行查詢,導致查出多行
4.INDEX UNIQUE SCANS
掃描唯一索引或主鍵,要麼返回一行數據要麼返回0行數據
1.當使用唯一索引時 
2.當使用主鍵時
5.INDEX SKIP SCANS
其實質是將索引分解成多個小的子索引來提高效率,系從9i開始引入
複合索引中前導列的取值是枚舉的從而可以分拆爲多個子索引,並且查詢條件中不含前導列時
 
爲了 加深鞏固前面的知識,本處對前五種索引掃描複習總結如下:
(1).全索引掃描
逐一讀取索引中的所有塊,由於索引中數據已按索引鍵排序,因此會忽略掉排序,可能發生的情況如下:
A. ORDER BY中的列全部在某個索引中
   全部在某個索引中:
 
(1).全索引掃描
B. ORDER BY中列的順序滿足索引中前導列的順序時
  下面分別是滿足和不滿足前導列順序時:
C. 使用GROUP BY且該子句中的列在索引中時
(2).快速全索引掃描
只掃描索引中的數據,不會掃描表中的數據;由於索引中數據未按索引鍵排序,因此不能忽略掉排序。當同時滿足下列條件時,Oracle用FFIS替代FIS或FTS:
1.查詢的所有列均包含在索引中
2.索引中的列至少一個具有not null約束(10g開始的,原低版本的系統中爲查詢的列中不包含任何null值)
 
全部列均在索引中:
 
 
  有列不在索引中:
 
刪除該索引,創建新索引,兩個列均爲可空:
此時即使全部列在該索引中,  也不會發生FFIS
索引範圍掃描是訪問選擇性數據最常用的掃描方式;按順序的對某個索引進行掃描,返回數據是升序排列的,可以使用唯一索引和非唯一索引;如果對索引列使用ORDER BY/GROUP BY則可省略排序。
下列情形中會發生索引範圍掃描:
A.在唯一索引上使用範圍操作符(>、<、>=、<=、<>、BETWEEN)
B.在組合索引上使用部分列進行查詢,導致查出多行
示例請參考本系列課程的索引章節部分
 
(4).索引唯一掃描
  當使用主鍵或唯一索引時發生。 示例請參考本系列課程的索引章節部分。
(5).索引跳躍掃描
    複合索引中前導列的取值是枚舉的從而可以分拆爲多個子索引,並且查詢條件中不含前導列時。示例如下:
create table customers as select * from sh.customers;
CREATE INDEX customers_gender_email
  ON customers (cust_gender, cust_email);
 
(5).索引跳躍掃描
 沒進行表分析前:
  
 進行表分後:
   analyze table customers compute statistics;
  
 
何時需要索引
一般地,對於從表的總行中的大部分查詢只查詢不到10%數據(有的稱爲2%-4%)的表,可以考慮創建索引。一般考慮的索引的原則包括:
 
l對於經常以查詢關鍵字爲基礎的表,並且該表中的數據行是均勻分佈的
l以查詢關鍵字爲基礎,表中的數據行隨機排序
l表中包含的列數相對比較少(僅僅是相對,需要根據實際情況確定)
l表中的大多數查詢都包含相對簡單的WHERE子句
l表的記錄數比較少的,不建議使用索引,如數據不超過1萬行的表不要建立索
 
 
爲索引選擇列和表達式
一般遵循的原則包括:
l經常在WHERE子句中使用的列
lSQL語句中經常用於表之間連接的列
l重複性少(可選擇性高)的關鍵字,如主鍵
l不宜將經常UPDATE的列作爲索引列
l不宜將經常在WHERE子句中使用,但與函數或操作符相結合的列作爲索引列
l對於取值較少的列,應考慮建立位圖索引,而不應該採用B樹索引
l如果經常訪問的列上要使用函數,應使用基於函數的索引
 
本處舉例說明取值較少的列使用bitmap索引和b-tree的對比分析,B-tree時:
 
 
bitmap時:
 
 
使用複合索引
  多個列聯合起來組成的索引稱爲複合索引、或聯合索引或者組合索引,往往聯合索引比單個索引具有更好的性能。創建聯合索引一般遵循的原則包括:
l經常在WHERE子句中使用的列且這些列之間使用AND連接
l查詢條件可能包括n個列的AND關係,而大多數情況下使用m個列是(n>m),應該考慮複合索引,且n個列爲前導列
l某幾個列聯合起來能夠組成唯一索引,應堅決建立聯合唯一索引
l複合索引中,建議至少一個不能爲null,且如果可能儘量將只是存在null的列對其null值採用其它默認值代替
 
本處舉例說明Where中包含AND時使用多個索引性能低於聯合索引的示例,使用多個索引時:
 
 
 
本處舉例說明Where中包含AND是使用多個索引性能低於聯合索引的示例,使用複合索引時:
 
 
結論:
項目
多個索引
複合索引
複合索引是多個索引的
一、執行時間
0.281
0.11
39.15%
二、執行計劃
     
1.總耗費
1658
464
27.99%
2.I/O耗費
1562
462
29.58%
3.時間
19
6
31.58%
可見,此時複合索引是多個索引的效率的 四倍以上!
監視索引的使用情況
u正確合適的索引是查詢優化性能的首選
u索引是表的索引列排序後的小型化拷貝,會增加存儲開銷,因此會帶來Insert、Update、Delete的額外開銷
u一個表可以有一個索引,也可以有多個索引,往往過多的索引或不恰當的索引帶來的負面性能更多
u表索引的設計初衷,往往在40%甚至更高的情況下與最終的實際使用情況不符合,此舉視設計人員對業務和Oracle的理解不同而不同
u監視索引的實際使用情況,尤其在表具有多個索引的情況下,就顯得尤爲重要,對經常不使用的索引採用合併爲複合索引或刪除是優化的工作之一
示例如下:
1.創建索引
  
2.啓用所以監視
  
3.執行SQL
  
 
 
4.查看索引使用情況
 
我們可以根據一個持續時間的對索引的監控結果決定如何合併及刪除不恰當的索引。
5.停止監視索引
 
 轉載請註明私塾在線【 http://sishuok.com/forum/blogPost/list/6414.html
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章