為什麼Oracle資料庫不用索引來查詢資料?

2021-05-24 10:39:11 字數 2545 閱讀 9715

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上的索引顯然是用不上,最多在其上做索引全掃瞄或索引快速全掃瞄。

第五,是否用到系統資料字典表或檢視。由於系統資料字典表都未被分析過,可能導致極差的「執行計畫」。但是不要擅自對資料字典表做分析,否則可能導致死鎖,或系統效能下降。

如我們想要用到a表的ind_col1索引的話,可採用以下方式:

「select /*+ index(a ind_col1)*/ * from a where col1 = ***;"

注意,注釋符必須跟在select之後,且注釋中的「+」要緊跟著注釋起始符「/*」或「--」,否則hint就被認為是一般注釋,對pl/sql語句的執行不產生任何影響。

兩種有效的跟蹤除錯方法

oracle提供了兩種有效的工具來跟蹤除錯pl/sql語句的執行計畫。

一種是explain table方式。使用者必須首先在自己的模式(schema)下,建立plan_table表,執行計畫的每一步驟都將記錄在該表中,建表sql指令碼為在$/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__***x.trc檔案,其中***x為被跟蹤應用的作業系統程序號。

應用程式執行完成後,用命令tkprof對該檔案進行分析。命令示例:「tkprof tracefile outputfile explain=userid/password"。在作業系統oracle使用者下,鍵入「tkprof」,會有詳細的命令幫助。分析後的輸出檔案outputfile中,有每一條pl/sql語句的「執行計畫」、cpu占用、物理讀次數、邏輯讀次數、執行時長等重要資訊。根據輸出檔案的資訊,我們可以很快發現應用中哪條pl/sql語句是問題的癥結所在。 

為什麼有時ORACLE資料庫不用索引來查詢資料

為什麼有時oracle資料庫不用索引來查詢資料?sql語句的執行步驟 一條sql語句的處理過程要經過以下幾個步驟。1 語法分析 分析語句的語法是否符合規範,衡量語句中各表示式的意義。2 語義分析 檢查語句中涉及的所有資料庫物件是否存在,且使用者有相應的許可權。3 檢視轉換 將涉及檢視的查詢語句轉換為...

為什麼有時 Oracle 資料庫不用索引來查詢資料

sql 語句的執行步驟。1 語法分析 分析語句的語法是否符合規範,衡量語句中各表示式的意義。2 語義分析 檢查語句中涉及的所有資料庫物件是否存在,且使用者有相應的許可權。3 檢視轉換 將涉及檢視的查詢語句轉換為相應的對基表查詢語句。4 表示式轉換 將複雜的 sql 表示式轉換為較簡單的等效連線表示式...

域控有什麼好處 為什麼我們不用資料庫生成 ID?

先介紹一下背景 團隊正在乙個為 sql server 構建資料目錄專案的歷程中,我們優化系統以實現解耦。這對我們來說非常重要,從根本上來說,我歸結為兩個核心原則,希望每個軟體專業人員都能認同 對持久化有何影響?考慮到前面總體原則,我們不想把自己的狀態持久化耦合到乙個特定的資料庫引擎上。從實際情況來看...