B-樹索引在Oracle中是壹個通用的索引,在創建索引時它就是默認的索引類型。最多可以包括32列。
位圖索引Oracle為每個唯壹鍵創建壹個位圖,然後把與鍵值所關聯的ROWID保存為位圖。最多可以包括30列。
壹般情況下,大多數用戶都只創建TYPE為NORMAL的B-樹索引,所以對於較低基數的列我們都是不創建索引的,因為B-樹索引對查詢速度提升不壹定會有改善,甚至會增加Insert、Update、Delete命令所消耗的時間。
位圖索引在加載表(插入操作)時通常要比B-樹索引做得好。通常,位圖索引要比壹個低基數(很少不同值)上的B-樹索引要快3~4倍,但如果新增的值占插入行的70%以上時,B-樹索引通常會更快壹些。當每條記錄都增加壹個新值時,B-樹索引要比位圖索引快3倍。
建議不要在壹些聯機事務處理(OLTP)應用程序中使用位圖索引。B-樹索引的索引值中包含ROWID,這樣Oracle就可以在行級別上鎖定索引。位圖索引被存儲為壓縮的索引值,其中包含了壹個範圍內的ROWID,因此ORACLE必須針對壹個給定值鎖定所有範圍內的ROWID。這種鎖定可能自阿某些DML語句中造成死鎖。SELECT語句不會受到這種鎖定問題的影響。
位圖索引有很多限制:
1、 基於規則的優化器不會考慮位圖索引
2、 當執行ATLER TABLE語句,並修改包含有位圖索引的列時,會使位圖索引實效
3、 位圖索引在索引塊中儲存了索引鍵的值;然而,他們並不能用戶任何類型的完整性檢查
4、 位圖索引不能被申明為唯壹索引
以上是援引的壹些簡單概念,下面是我實際工作中總結出來的:
我要做壹個查詢,涉及兩個表t_sym_dict,t_sym_operlog,表結構分別如下:
oracle的索引使用oracle的索引使用
其中t_sym_operlog的索引如下:
oracle的索引使用
上面基數比較小的三列創建了位圖索引
t_sym_dict的索引如下:
oracle的索引使用
查詢語句如下:
select (select c.dict_name
from t_sym_dict c
where c.dict_typeid = 'SYM_CITYINFO'
and c.dict_id = t.memo) 分公司,
t.staff_id 工號
from t_sym_operlog t
where t.operlog_subtype = '103'
and t.obj_type = 'CUSTLINKINFO'
and t.memo = '200'
-- and t.extsys_code = ''
-- and t.staff_id = ''
and t.oper_date >= to_date('20110501000000', 'yyyymmddhh24miss')
and t.oper_date <= to_date('20110530000000', 'yyyymmddhh24miss')
-- order by t.memo, t.oper_date
然後就出現了如下奇怪的現象(索引的創建沒有問題)
1、索引使用正常
oracle的索引使用
2、下面的看不到oper_date索引的使用
oracle的索引使用
3、下面的看不到t_sym_operlog表的索引使用
oracle的索引使用
嘗試的解決的辦法:
對數據表做采集,就是analysis
BEGIN
DBMS_STATS.gather_table_stats(ownname => 'CSID',tabname => 't_sym_operlog_back');
end;
猜測的導致原因:
當妳運用SQL語言,向數據庫發布壹條查詢語句時,ORACLE將伴隨產生壹個“執行計劃”,也就是該語句將通過何種數據搜索方案執行,是通過全表掃描、還是通過索引搜尋等其它方式。搜索方案的選用與ORACLE的優化器息息相關。
SQL語句的執行步驟
壹條SQL語句的處理過程要經過以下幾個步驟。
1 語法分析 分析語句的語法是否符合規範,衡量語句中各表達式的意義。
2 語義分析 檢查語句中涉及的所有數據庫對象是否存在,且用戶有相應的權限。
3 視圖轉換 將涉及視圖的查詢語句轉換為相應的對基表查詢語句。
4 表達式轉換 將復雜的SQL表達式轉換為較簡單的等效連接表達式。
5 選擇優化器 不同的優化器壹般產生不同的“執行計劃”
6 選擇連接方式 ORACLE有三種連接方式,對多表連接ORACLE可選擇適當的連接方式。
7 選擇連接順序 對多表連接ORACLE選擇哪壹對表先連接,選擇這兩表中哪個表做為源數據表。
8 選擇數據的搜索路徑 根據以上條件選擇合適的數據搜索路徑,如是選用全表搜索還是利用索引或是其他的方式。
9 運行“執行計劃”
分析:
oracle優化器CBO存在的典型問題:
有時,表明明建有索引,但查詢過程顯然沒有用到相關的索引,導致查詢過程耗時漫長,占用資源巨大,問題到底出在哪兒呢?按照以下順序查找,基本上能發現原因所在。
查找原因的步驟
首先,我們要確定數據庫運行在何種優化模式下,相應的參數是:optimizer_mode。可在svrmgrl中運行“show parameter optimizer_mode"來查看。ORACLE V7以來缺省的設置應是"choose",即如果對已分析的表查詢的話選擇CBO,否則選擇RBO。如果該參數設為“rule”,則不論表是否分析過,壹概選用RBO,除非在語句中用hint強制。
其次,檢查被索引的列或組合索引的首列是否出現在PL/SQL語句的WHERE子句中,這是“執行計劃”能用到相關索引的必要條件。
第三,看采用了哪種類型的連接方式。ORACLE的***有Sort Merge Join(SMJ)、Hash Join(HJ)和Nested Loop Join(NL)。在兩張表連接,且內表的目標列上建有索引時,只有Nested Loop才能有效地利用到該索引。SMJ即使相關列上建有索引,最多只能因索引的存在,避免數據排序過程。HJ由於須做HASH運算,索引的存在對數據查詢速度幾乎沒有影響。
第四,看連接順序是否允許使用相關索引。假設表emp的deptno列上有索引,表dept的列deptno上無索引,WHERE語句有emp.deptno=dept.deptno條件。在做NL連接時,emp做為外表,先被訪問,由於連接機制原因,外表的數據訪問方式是全表掃描,emp.deptno上的索引顯然是用不上,最多在其上做索引全掃描或索引快速全掃描。
第五,是否用到系統數據字典表或視圖。由於系統數據字典表都未被分析過,可能導致極差的“執行計劃”。但是不要擅自對數據字典表做分析,否則可能導致死鎖,或系統性能下降。
第六,索引列是否函數的參數。如是,索引在查詢時用不上。
第七,是否存在潛在的數據類型轉換。如將字符型數據與數值型數據比較,ORACLE會自動將字符型用to_number()函數進行轉換,從而導致第六種現象的發生。
第八,是否為表和相關的索引搜集足夠的統計數據。對數據經常有增、刪、改的表最好定期對表和索引進行分析,可用SQL語句“analyze table xxxx compute statistics for all indexes;"。ORACLE掌握了充分反映實際的統計數據,才有可能做出正確的選擇。
第九,索引列的選擇性不高。
我們假設典型情況,有表emp,***有壹百萬行數據,但其中的emp.deptno列,數據只有4種不同的值,如10、20、30、40。雖然emp數據行有很多,ORACLE缺省認定表中列的值是在所有數據行均勻分布的,也就是說每種deptno值各有25萬數據行與之對應。假設SQL搜索條件DEPTNO=10,利用deptno列上的索引進行數據搜索效率,往往不比全表掃描的高,ORACLE理所當然對索引“視而不見”,認為該索引的選擇性不高。
但我們考慮另壹種情況,如果壹百萬數據行實際不是在4種deptno值間平均分配,其中有99萬行對應著值10,5000行對應值20,3000行對應值30,2000行對應值40。在這種數據分布圖案中對除值為10外的其它deptno值搜索時,毫無疑問,如果索引能被應用,那麽效率會高出很多。我們可以采用對該索引列進行單獨分析,或用analyze語句對該列建立直方圖,對該列搜集足夠的統計數據,使ORACLE在搜索選擇性較高的值能用上索引。
第十,索引列值是否可為空(NULL)。如果索引列值可以是空值,在SQL語句中那些需要返回NULL值的操作,將不會用到索引,如COUNT(*),而是用全表掃描。這是因為索引中存儲值不能為全空。
第十壹,看是否有用到並行查詢(PQO)。並行查詢將不會用到索引。
第十二,看PL/SQL語句中是否有用到bind變量。由於數據庫不知道bind變量具體是什麽值,在做非相等連接時,如“<”,“>”,“like”等。ORACLE將引用缺省值,在某些情況下會對執行計劃造成影響。
如果從以上幾個方面都查不出原因的話,我們只好用采用在語句中加hint的方式強制ORACLE使用最優的“執行計劃”。
hint采用註釋的方式,有行註釋和段註釋兩種方式。
如我們想要用到A表的IND_COL1索引的話,可采用以下方式:
“SELECT * FROM A WHERE COL1 = XXX;"
註意,註釋符必須跟在SELECT之後,且註釋中的“+”要緊跟著註釋起始符“/*”或“--”,否則hint就被認為是壹般註釋,對PL/SQL語句的執行不產生任何影響。
兩種有效的跟蹤調試方法
ORACLE提供了兩種有效的工具來跟蹤調試PL/SQL語句的執行計劃。
壹種是EXPLAIN TABLE方式。用戶必須首先在自己的模式(SCHEMA)下,建立PLAN_TABLE表,執行計劃的每壹步驟都將記錄在該表中,建表SQL腳本為在${ORACLE_HOME}/rdbms/admin/下的utlxplan.sql。
打開SQL*PLUS,輸入“SET AUTOTRACE ON”,然後運行待調試的SQL語句。在給出查詢結果後,ORACLE將顯示相應的“執行計劃”,包括優化器類型、執行代價、連接方式、連接順序、數據搜索路徑以及相應的連續讀、物理讀等資源代價。
如果我們不能確定需要跟蹤的具體SQL語句,比如某個應用使用壹段時間後,響應速度忽然變慢。我們這時可以利用ORACLE提供的另壹個有力工具TKPROF,對應用的執行過程全程跟蹤。
我們要先在系統視圖V$SESSION中,可根據USERID或MACHINE,查出相應的SID和SERIAL#。
以SYS或其他有執行DBMS_SYSTEM程序包的用戶連接數據庫,執行“EXECUTE DBMS_SYSTEM.SET_SQL_TRACE_IN_SESSION(SID,SERIAL#,TRUE);”。
然後運行應用程序,這時在服務器端,數據庫參數“USER_DUMP_DEST”指示的目錄下,會生成ora__xxxx.trc文件,其中xxxx為被跟蹤應用的操作系統進程號。
應用程序執行完成後,用命令tkprof對該文件進行分析。命令示例:“tkprof tracefile outputfile explain=userid/password"。在操作系統ORACLE用戶下,鍵入“tkprof”,會有詳細的命令幫助。分析後的輸出文件outputfile中,有每壹條PL/SQL語句的“執行計劃”、CPU占用、物理讀次數、邏輯讀次數、執行時長等重要信息。根據輸出文件的信息,我們可以很快發現應用中哪條PL/SQL語句是問題的癥結所在。