較典型的問題有:有時,表明明建有索引,但查詢過程顯然沒有用到相關的索引,導致查詢過程耗時漫長,佔用資源巨大,問題到底出在哪兒呢?按照以下順序尋找,基本上能發現原因所在。
尋找原因的步驟
首先,我們要確定資料庫運行在何種最佳化模式下,相應的參數是:optimizer_mode。可在svrmgrl中運行“showparameteroptimizer_mode"來查看。ORACLEV7以來預設的設定應是"choose",即如果對已分析的表查詢的話選擇CBO,否則選擇RBO。如果該參數設為“rule”,則不論表是否分析過,一
概選用RBO,除非在語句中用hint強制。
其次,檢查被索引的列或複合式索引的首列是否出現在PL/SQL語句的WHERE子句中,這是“執行計畫”能
用到相關索引的必要條件。
第三,看採用了哪種類型的串連方式。ORACLE的共有SortMergeJoin(SMJ)、HashJoin(HJ)和NestedLoopJoin(NL)。在兩張表串連,且內表的目標列上建有索引時,只有NestedLoop才能有效地利用到該索引。SMJ即使相關列上建有索引,最多隻能因索引的存在,避免資料排序過程。HJ由於須做HASH運算,索引的存在對資料查詢速度幾乎沒有影響。
第四,看串連順序是否允許使用相關索引。假設表emp的deptno列上有索引,表dept的列deptno上無索引,WHERE語句有emp.deptno=dept.deptno條件。在做NL串連時,emp做為外表,先被訪問,由於串連機制原因,外表的資料訪問方式是全表掃描,emp.deptno上的索引顯然是用不上,最多在其上
做索引全掃描或索引快速全掃描。
第五,是否用到系統資料字典表或視圖。由於系統資料字典表都未被分析過,可能導致極差的“執行計畫”。但是不要擅自對資料字典表做分析,否則可能導致死結,或系統效能下降。
第六,是否存在潛在的資料類型轉換。如將字元型資料與數值型資料比較,ORACLE會自動將字元型用to_number()函數進行轉換,從而導致第六種現象的發生。
第七,是否為表和相關的索引搜集足夠的統計資料。對資料經常有增、刪、改的表最好定期對錶和索引進行分析,可用SQL語句“analyzetablexxxxcomputestatisticsforallindexes;"。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)。並行查詢將不會用到索引。如我們想要用到A表的IND_COL1索引的話,可採用以下方式:“SELECT/*+INDEX(AIND_COL1)*/*FROMAWHERECOL1=XXX;"注意,注釋符必須跟在SELECT之後,且注釋中的“+”要緊跟著注釋起始符“/*”或“--”,否則hint就被認為是一般注釋,對PL/SQL語句的執行不產生任何影響。一種是EXPLAINTABLE方式。使用者必須首先在自己的模式(SCHEMA)下,建立PLAN_TABLE表,執行計畫的每一步驟都將記錄在該表中,建表SQL指令碼為在${ORACLE_HOME}/rdbms/admin/下的utlxplan.sql
。
開啟SQL*PLUS,輸入“SETAUTOTRACEON”,然後運行待調試的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對該檔案進行分析。命令樣本:“tkproftracefileoutputfileexplain=userid/password"。在作業系統ORACLE使用者下,鍵入“tkprof”,會有詳細的命令協助。分析後的輸出檔案outputfile中,有每一條PL/SQL語句的“執行計畫”、CPU佔用、物理讀次數、邏輯讀次數、執行時間長度等重要訊息。根據輸出檔案的資訊,我們可以很快發現應用中哪條PL/SQL語句是問題的癥結所在.