為什麼有時Oracle資料庫不用索引來查詢資料?(轉)
當你運用SQL語言,向資料庫釋出一條查詢語句時,ORACLE將伴隨產生一個“執行計劃”,也就是該語句將透過何種資料搜尋方案執行,是透過全表掃描、還是透過索引搜尋等其它方式。搜尋方案的選用與ORACLE的最佳化器息息相關。
SQL語句的執行步驟
一條SQL語句的處理過程要經過以下幾個步驟。
1 語法分析 分析語句的語法是否符合規範,衡量語句中各表示式的意義。
2 語義分析 檢查語句中涉及的所有資料庫物件是否存在,且使用者有相應的許可權。
3 檢視轉換 將涉及檢視的查詢語句轉換為相應的對基表查詢語句。
4 表示式轉換 將複雜的SQL表示式轉換為較簡單的等效連線表示式。
5 選擇最佳化器 不同的最佳化器一般產生不同的“執行計劃”
6 選擇連線方式 ORACLE有三種連線方式,對多表連線ORACLE可選擇適當的連線方式。
7 選擇連線順序 對多表連線ORACLE選擇哪一對錶先連線,選擇這兩表中哪個表做為源資料表。
8 選擇資料的搜尋路徑 根據以上條件選擇合適的資料搜尋路徑,如是選用全表搜尋還是利用索引或是其他的方式。
9 執行“執行計劃”
ORACLE的最佳化器
ORACLE有兩種最佳化器:基於規則的最佳化器(RBO, Rule Based Optimizer),和基於代價的最佳化器(CBO, Cost Based Optimizer)。
RBO自ORACLE 6版以來被採用,有著一套嚴格的使用規則,只要你按照它去寫SQL語句,無論資料表中的內容怎樣,也不會影響到你的“執行計劃”,也就是說對資料不“敏感”,ORACLE公司已經不再發展這種技術了。
CBO自ORACLE 7版被引入,ORACLE自7版以來採用的許多新技術都是基於CBO的,如星型連線排列查詢,雜湊連線查詢,和並行查詢等。CBO計算各種可能“執行計劃”的“代價”,即cost,從中選用cost最低的方案,作為實際執行方案。各“執行計劃”的cost的計算根據,依賴於資料表中資料的統計分佈,ORACLE資料庫本身對該統計分佈並不清楚,須要分析表和相關的索引,才能蒐集到CBO所需的資料。
一般而言,CBO所選擇的“執行計劃”都不會比RBO的“執行計劃”差,而且相對而言,CBO對程式設計師的要求沒有RBO那麼苛刻,節省了程式設計師為了從多個可能的“執行計劃”中選擇一個最優的方案而花費的除錯時間,但在某些場合下也會存在問題。
較典型的問題有:有時,表明明建有索引,但查詢過程顯然沒有用到相關的索引,導致查詢過程耗時漫長,佔用資源巨大,問題到底出在哪兒呢?按照以下順序查詢,基本上能發現原因所在。
查詢原因的步驟
首先,我們要確定資料庫執行在何種最佳化模式下,相應的引數是: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 /*+ INDEX(A IND_COL1)*/ * 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語句是問題的癥結所在。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10748419/viewspace-954148/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 為什麼不用資料庫儲存圖片?資料庫
- 時序資料庫-01-時序資料庫有哪些?為什麼要使用資料庫
- 為資料庫建立索引(轉)資料庫索引
- 資料庫索引為什麼使用B+樹?資料庫索引
- Prometheus時序資料庫-資料的查詢Prometheus資料庫
- 關於Oracle資料庫的時間查詢Oracle資料庫
- 【YashanDB資料庫】yasboot查詢資料庫狀態時顯示資料庫狀態為off資料庫boot
- 資料庫 - 資料查詢資料庫
- 比較有索引和無索引的查詢速度(在mysql資料庫中)索引MySql資料庫
- 概括SQL Server實時查詢Oracle資料庫WSSQLServerOracle資料庫
- (利用索引)大資料查詢索引大資料
- 資料庫資料的查詢----連線查詢資料庫
- 資料庫查詢和資料庫(MySQL)索引的最佳化建議資料庫MySql索引
- 提高ORACLE資料庫的查詢統計速度(轉)Oracle資料庫
- 資料庫索引是什麼?新華字典來幫你資料庫索引
- 資料庫查詢資料庫
- 資料庫索引為什麼用B+樹實現?資料庫索引
- Oracle資料庫的查詢變慢了Oracle資料庫
- 【資料庫】簡單聊聊資料庫可以做什麼,有什麼用?資料庫
- 【資料庫】雲資料庫rds是什麼意思?有什麼優勢?資料庫
- 資料庫外來鍵,用是不用?資料庫
- Oracle 查詢行數很少,為什麼不走索引?Oracle索引
- indexedDB 通過索引查詢資料Index索引
- mysql資料庫查詢時用到的分頁方法有哪些MySql資料庫
- 為什麼會有這麼多種的資料庫資料庫
- Oracle資料庫索引使用及索引失效總結 轉Oracle資料庫索引
- 資料庫索引原理-轉資料庫索引
- 玩轉資料庫索引資料庫索引
- 求助:資料庫查詢資料庫
- ThinkPHP 資料庫查詢PHP資料庫
- 查詢資料庫大小資料庫
- 資料庫排序查詢資料庫排序
- Jemter查詢資料庫資料庫
- 雲資料庫RDS是什麼?雲資料庫RDS有什麼優勢?資料庫
- 什麼是資料實時同步,為什麼資料實時同步很重要
- [資料庫]資料庫中為什麼不推薦使用外來鍵約束資料庫
- Oracle資料庫中索引的維護(轉)Oracle資料庫索引
- oracle資料庫建立Squence序列並查詢Oracle資料庫