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

2023-02-05 08:00:03 字數 4589 閱讀 3257

為什麼有時 oracle 資料庫不用索引來查詢資料(一)

當你運用 sql 語言,向資料庫發布一條查詢語句時, oracle 將伴隨產生乙個執行計畫,也就是該語句將通過何種資料搜尋方案執行,是通過全表掃瞄、還是通過索引搜尋等其它方式。搜尋方案的選用與 oracle 的優化器息息相關。

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 語句有 條件。在做 nl 連線時, emp 做為外表,先被訪問,由於連線機制原因,外表的資料訪問方式是全表掃瞄, 上的索引顯然是用不上,最多在其上做索引全掃瞄或索引快速全掃瞄。

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

第六,是否存在潛在的資料型別轉換。如將字元型資料與數值型資料比較, oracle 會自動將字元型用 to_number() 函式進行轉換,從而導致第六種現象的發生。

為什麼有時 oracle 資料庫不用索引來查詢資料(二)

第七,是否為表和相關的索引蒐集足夠的統計資料。對資料經常有增、刪、改的表最好定期對錶和索引進行分析,可用 sql 語句 analyze table ***x compute statistics for all indexes;" 。 oracle 掌握了充分反映實際的統計資料,才有可能做出正確的選擇。

第八,索引列的選擇性不高。 我們假設典型情況,有表 emp ,共有一百萬行資料,但其中的 列,資料只有 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 ( a ind_col1 ) */ * from a where col1 = ***;"

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

一種是 explain table 方式。使用者必須首先在自己的模式( schema )下,建立 plan_table 表,執行計畫的每一步驟都將記錄在該表中,建表 sql 指令碼為在 $/rdbms/admin/ 下的 。

開啟 sql*plus ,輸入 set autotrace on ,然後執行待除錯的 sql 語句。在給出查詢結果後, oracle 將顯示相應的執行計畫,包括優化器型別、執行代價、連線方式、連線順序、資料搜尋路徑以及相應的連續讀、物理讀等資源代價。

如果我們不能確定需要跟蹤的具體 sql 語句,比如某個應用使用一段時間後,響應速度忽然變慢。我們這時可以利用 oracle 提供的另乙個有力工具 tkprof ,對應用的執行過程全程跟蹤。

我們要先在系統檢視 v$session 中,可根據 userid 或 machine ,查出相應的 sid 和 serial# 。

以 sys 或其他有執行 dbms_system 程式包的使用者連線資料庫,執行 execute dbms_ ( sid , serial# , true );。

然後執行應用程式,這時在伺服器端,資料庫引數 user_dump_dest 指示的目錄下,會生成 ora__ 檔案,其中 ***x 為被跟蹤應用的作業系統程序號。

應用程式執行完成後,用命令 tkprof 對該檔案進行分析。命令示例: tkprof tracefile outputfile explain=userid/password" 。

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

oracleindex的三個問題(三)

oracle index 的三個問題(三)

第三講、索引再好,不用也是白搭

拋開前面所說的,假設你設定了乙個非常好的索引,任何傻瓜都知道應該使用它,但是 oracle 卻偏偏不用,那麼,需要做的第一件事情,是審視你的 sql 語句。

oracle 要使用乙個索引,有一些最基本的條件:

1 , where 子句中的這個字段,必須是復合索引的第乙個字段;

2 , where 子句中的這個字段,不應該參與任何形式的計算

具體來講,假設乙個索引是按 f1, f2, f3 的次序建立的,現在有乙個 sql 語句 , where 子句是 f2 = : var2, 則因為 f2 不是索引的第 1 個字段,無法使用該索引。

第 2 個問題,則在我們之中非常嚴重。以下是從實際系統上面抓到的幾個例子:

select jobid from mytabs where isreq=0 and to_date (updatedate) >= to_date ( 2001-7-18, yyyy-mm-dd) ;

oracle資料庫入門

很多剛剛接觸oracle資料庫的初學者總是感覺oracle很難學,無從下手,漸漸的感覺對oracle很排斥,有的朋友找了本oracle是書也是一點也看不懂,或者看了前面幾章,還是不知道怎麼用。其實,從筆者的親身經歷來說,oracle入門很簡單,使用oracle的基本功能也是一件非常簡單的事情。但是想...

Oracle資料庫知識總結

ad1.執行乙個sql指令碼檔案 sql start file name sql file name 我們可以將多條sql語句儲存在乙個文字檔案中,這樣當要執行這個檔案中的所有的sql語句時,用上面的任一命令即可,這類似於dos中的批處理。4.將顯示的內容輸出到指定檔案 sql spool file...

關於ORACLE資料庫索引

許娟萍1999.03.22 一 索引 索引不是執行oracle所必需的,但它能夠加快查詢速度。當執行同樣的查詢時,若有利用索引,oracle首先在索引中查詢,由於索引是按大小排列的,因此能很快找到查詢結果。乙個表的單個索引最多可以包含16個列。索引太多的代價是降低插入新行的速度 每做一次insert...