Oracle語句優化規則彙總(10)

1. 需要當心的WHERE子句

  某些SELECT 語句中的WHERE子句不使用索引。 這裏有一些例子。

  在下面的例子裏, ‘!=’ 將不使用索引。 記住, 索引只能告訴你什麼存在於表中, 而不能告訴你什麼不存在於表中。

  不使用索引:

SELECT ACCOUNT_NAME 
  FROM TRANSACTION 
  WHERE AMOUNT !=0;

  使用索引:

SELECT ACCOUNT_NAME 
  FROM TRANSACTION 
  WHERE AMOUNT >0;

  下面的例子中, ‘||’是字符連接函數。 就象其他函數那樣, 停用了索引。

  不使用索引:

SELECT ACCOUNT_NAME,AMOUNT 
  FROM TRANSACTION 
  WHERE ACCOUNT_NAME||ACCOUNT_TYPE=‘AMEXA’;

  使用索引:

SELECT ACCOUNT_NAME,AMOUNT 
  FROM TRANSACTION 
  WHERE ACCOUNT_NAME = ‘AMEX’AND ACCOUNT_TYPE=‘ A’;

  下面的例子中, ‘+’是數學函數。 就象其他數學函數那樣, 停用了索引。

不使用索引:

SELECT ACCOUNT_NAME, AMOUNT 
  FROM TRANSACTION 
  WHERE AMOUNT + 3000 >5000;

  使用索引:

SELECT ACCOUNT_NAME, AMOUNT 
  FROM TRANSACTION 
  WHERE AMOUNT > 2000 ;

  下面的例子中,相同的索引列不能互相比較,這將會啓用全表掃描。

  不使用索引:

SELECT ACCOUNT_NAME, AMOUNT 
  FROM TRANSACTION 
  WHERE ACCOUNT_NAME = NVL(:ACC_NAME,ACCOUNT_NAME);

  使用索引:

SELECT ACCOUNT_NAME, AMOUNT 
  FROM TRANSACTION 
  WHERE ACCOUNT_NAME LIKE NVL(:ACC_NAME,‘%’);

  :如果一定要對使用函數的列啓用索引, ORACLE新的功能: 基於函數的索引(Function-Based Index) 也許是一個較好的方案。

CREATE INDEX EMP_I ON EMP (UPPER(ename)); /*建立基於函數的索引*/ 
  SELECT * FROM emp WHERE UPPER(ename) = ‘BLACKSNAIL’; /*將使用索引*/

  2. 連接多個掃描

  如果你對一個列和一組有限的值進行比較, 優化器可能執行多次掃描並對結果進行合併連接。

  舉例:

SELECT * 
  FROM LODGING 
  WHERE MANAGER IN (‘BILL GATES’,‘KEN MULLER’);

  優化器可能將它轉換成以下形式

SELECT * 
  FROM LODGING 
  WHERE MANAGER = ‘BILL GATES’OR MANAGER = ‘KEN MULLER’;

  當選擇執行路徑時, 優化器可能對每個條件採用LODGING$MANAGER上的索引範圍掃描。 返回的ROWID用來訪問LODGING表的記錄 (通過TABLE ACCESS BY ROWID 的方式)。 最後兩組記錄以連接(CONCATENATION)的形式被組合成一個單一的集合。

  Explain Plan :

SELECT STATEMENT Optimizer=CHOOSE 
  CONCATENATION 
  TABLE ACCESS (BY INDEX ROWID) OF LODGING 
  INDEX (RANGE SCAN ) OF LODGING$MANAGER (NON-UNIQUE) 
  TABLE ACCESS (BY INDEX ROWID) OF LODGING 
  INDEX (RANGE SCAN ) OF LODGING$MANAGER (NON-UNIQUE)

  :本節和第37節似乎有矛盾之處。

  3. CBO下使用更具選擇性的索引

  基於成本的優化器(CBO, Cost-Based Optimizer)對索引的選擇性進行判斷來決定索引的使用是否能提高效率。

  如果索引有很高的選擇性, 那就是說對於每個不重複的索引鍵值,只對應數量很少的記錄。

  比如, 表中共有100條記錄而其中有80個不重複的索引鍵值。 這個索引的選擇性就是80/100 = 0.8 . 選擇性越高, 通過索引鍵值檢索出的記錄就越少。

  如果索引的選擇性很低, 檢索數據就需要大量的索引範圍查詢操作和ROWID 訪問表的操作。 也許會比全表掃描的效率更低。

  :下列經驗請參閱:

  a. 如果檢索數據量超過30%的表中記錄數。使用索引將沒有顯著的效率提高。

  b. 在特定情況下, 使用索引也許會比全表掃描慢, 但這是同一個數量級上的區別。 而通常情況下,使用索引比全表掃描要快幾倍乃至幾千倍!

  4. 避免使用耗費資源的操作

  帶有DISTINCT,UNION,MINUS,INTERSECT,ORDER BY的SQL語句會啓動SQL引擎執行耗費資源的排序(SORT)功能。 DISTINCT需要一次排序操作, 而其他的至少需要執行兩次排序。

  例如,一個UNION查詢,其中每個查詢都帶有GROUP BY子句, GROUP BY會觸發嵌入排序(NESTED SORT) ; 這樣, 每個查詢需要執行一次排序, 然後在執行UNION時, 又一個唯一排序(SORT UNIQUE)操作被執行而且它只能在前面的嵌入排序結束後才能開始執行。 嵌入的排序的深度會大大影響查詢的效率。

通常, 帶有UNION, MINUS , INTERSECT的SQL語句都可以用其他方式重寫。

  :如果你的數據庫的SORT_AREA_SIZE調配得好, 使用UNION , MINUS, INTERSECT也是可以考慮的, 畢竟它們的可讀性很強

  5. 優化GROUP BY

  提高GROUP BY 語句的效率, 可以通過將不需要的記錄在GROUP BY 之前過濾掉。下面兩個查詢返回相同結果但第二個明顯就快了許多。

  低效:

SELECT JOB , AVG(SAL) 
  FROM EMP 
  GROUP by JOB 
  HAVING JOB = ‘PRESIDENT’ 
  OR JOB = ‘MANAGER’

  高效:

SELECT JOB , AVG(SAL) 
  FROM EMP 
  WHERE JOB = ‘PRESIDENT’ 
  OR JOB = ‘MANAGER’GROUP by JOB

  6. 使用日期當

  使用日期是,需要注意如果有超過5位小數加到日期上, 這個日期會進到下一天!

  例如:

  1.

SELECT TO_DATE(‘01-JAN-93’+.99999) 
  FROM DUAL; 
  Returns:“01-JAN-93 23:59:59‘

  2.

SELECT TO_DATE(’01-JAN-93‘+.999999) 
  FROM DUAL; 
  Returns:“02-JAN-93 00:00:00‘

  :雖然本節和SQL性能優化沒有關係, 但是作者的功力可見一斑。

7. 使用顯式的遊標(CURSORs)

  使用隱式的遊標,將會執行兩次操作。 第一次檢索記錄, 第二次檢查TOO MANY ROWS 這個exception . 而顯式遊標不執行第二次操作。

  8. 優化EXPORT和IMPORT

  使用較大的BUFFER(比如10MB , 10,240,000)可以提高EXPORT和IMPORT的速度。

  ORACLE將儘可能地獲取你所指定的內存大小,即使在內存不滿足,也不會報錯。這個值至少要和表中最大的列相當,否則列值會被截斷。

  :可以肯定的是, 增加BUFFER會大大提高EXPORT , IMPORT的效率。 (曾經碰到過一個CASE, 增加BUFFER後,IMPORT/EXPORT快了10倍!)

  作者可能犯了一個錯誤: “這個值至少要和表中最大的列相當,否則列值會被截斷。 ”其中最大的列也許是指最大的記錄大小。

  關於EXPORT/IMPORT的優化,CSDN論壇中有一些總結性的貼子,比如關於BUFFER參數, COMMIT參數等等, 詳情請查。

  9. 分離表和索引

  總是將你的表和索引建立在不同的表空間內(TABLESPACES)。 決不要將不屬於ORACLE內部系統的對象存放到SYSTEM表空間裏。 同時,確保數據表空間和索引表空間置於不同的硬盤上。

  :“同時,確保數據表空間和索引表空間置與不同的硬盤上。”可能改爲如下更爲準確 “同時,確保數據表空間和索引表空間置與不同的硬盤控制卡控制的硬盤上。”


發佈了12 篇原創文章 · 獲贊 5 · 訪問量 6萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章