資料查詢最佳化的方法

來源:互聯網
上載者:User
1.       用IN來替換OR
下面的查詢可以被更有效率的語句替換:
低效:
SELECT field1, field1 FROM LOCATION
WHERE LOC_ID = 10 OR     LOC_ID = 20 OR     LOC_ID = 30

高效
SELECT field1, field1 FROM LOCATION
WHERE LOC_IN IN (10,20,30)    
2.       串連多個掃描
如果你對一個列和一組有限的值進行比較, 最佳化器可能執行多次掃描並對結果進行合并串連.
舉例:
    SELECT * FROM LODGING
    WHERE MANAGER IN (‘BILL GATES’,’KEN MULLER’);
 
    最佳化器可能將它轉換成以下形式
    SELECT *  FROM LODGING
    WHERE MANAGER = ‘BILL GATES’
    OR MANAGER = ’KEN MULLER’;
3.       最佳化GROUP BY
提高GROUP BY 語句的效率, 可以通過將不需要的記錄在GROUP BY 之前過濾掉.下面兩個查詢返回相同結果但第二個明顯就快了許多.
低效:
   SELECT JOB , AVG(SAL) FROM EMP
   GROUP JOB HAVING JOB = ‘PRESIDENT’OR JOB = ‘MANAGER’
 高效:
   SELECT JOB , AVG(SAL) FROM EMP
   WHERE JOB = ‘PRESIDENT’OR JOB = ‘MANAGER’
   GROUP JOB  
4.       用>=替代>
如果DEPTNO上有一個索引, 
高效:
   SELECT *
   FROM EMP
   WHERE DEPTNO >=4
   
   低效:
   SELECT *
   FROM EMP
   WHERE DEPTNO >3

5.       用表串連替換EXISTS
     通常來說 , 採用表串連的方式比EXISTS更有效率
      SELECT ENAME
      FROM EMP E
      WHERE EXISTS (SELECT ‘X’ 
                      FROM DEPT
                      WHERE DEPT_NO = E.DEPT_NO
                      AND DEPT_CAT = ‘A’);

     (更高效)
      SELECT ENAME
      FROM DEPT D,EMP E
      WHERE E.DEPT_NO = D.DEPT_NO
      AND DEPT_CAT = ‘A’ ; 
6.       用EXISTS替換DISTINCT
當提交一個包含一對多表資訊(比如部門表和僱員表)的查詢時,避免在SELECT子句中使用DISTINCT. 一般可以考慮用EXIST替換 
低效:
    SELECT DISTINCT DEPT_NO,DEPT_NAME
    FROM DEPT D,EMP E
    WHERE D.DEPT_NO = E.DEPT_NO
高效:
    SELECT DEPT_NO,DEPT_NAME
    FROM DEPT D
    WHERE EXISTS ( SELECT ‘X’
                    FROM EMP E
                    WHERE E.DEPT_NO = D.DEPT_NO);

  EXISTS 使查詢更為迅速,因為RDBMS核心模組將在子查詢的條件一旦滿足後,立刻返回結果.
7.       使用表的別名(Alias)
當在SQL語句中串連多個表時, 請使用表的別名並把別名首碼於每個Column上.這樣一來,就可以減少解析的時間並減少那些由Column歧義引起的語法錯誤.
(譯者注: Column歧義指的是由於SQL中不同的表具有相同的Column名,當SQL語句中出現這個Column時,SQL解析器無法判斷這個Column的歸屬)

8.       用EXISTS替代IN
在許多基於基礎資料表的查詢中,為了滿足一個條件,往往需要對另一個表進行聯結.在這種情況下, 使用EXISTS(或NOT EXISTS)通常將提高查詢的效率.
低效:
SELECT * 
FROM EMP (基礎資料表)
WHERE EMPNO > 0
AND DEPTNO IN (SELECT DEPTNO 
FROM DEPT 
WHERE LOC = ‘MELB’)
高效: 
SELECT * 
FROM EMP (基礎資料表)
WHERE EMPNO > 0
AND EXISTS (SELECT ‘X’ 
FROM DEPT 
WHERE DEPT.DEPTNO = EMP.DEPTNO
AND LOC = ‘MELB’)
 (譯者按: 相對來說,用NOT EXISTS替換NOT IN 將更顯著地提高效率,下一節中將指出)
9.       用NOT EXISTS替代NOT IN
在子查詢中,NOT IN子句將執行一個內部的排序和合并. 無論在哪種情況下,NOT IN都是最低效的 (因為它對子查詢中的表執行了一個全表遍曆).  為了避免使用NOT IN ,我們可以把它改寫成外串連(Outer Joins)或NOT EXISTS.
例如:
SELECT …
FROM EMP
WHERE DEPT_NO NOT IN (SELECT DEPT_NO 
                         FROM DEPT 
                         WHERE DEPT_CAT=’A’);
為了提高效率.改寫為:
(方法一: 高效)
SELECT ….
FROM EMP A,DEPT B
WHERE A.DEPT_NO = B.DEPT(+)
AND B.DEPT_NO IS NULL
AND B.DEPT_CAT(+) = ‘A’
(方法二: 最高效)
SELECT ….
FROM EMP E
WHERE NOT EXISTS (SELECT ‘X’ 
                    FROM DEPT D
                    WHERE D.DEPT_NO = E.DEPT_NO
                    AND DEPT_CAT = ‘A’);
10.       減少對錶的查詢
在含有子查詢的SQL語句中,要特別注意減少對錶的查詢.
例如: 
     低效
          SELECT TAB_NAME
          FROM TABLES
          WHERE TAB_NAME = ( SELECT TAB_NAME 
                                FROM TAB_COLUMNS
                                WHERE VERSION = 604)
          AND DB_VER= ( SELECT DB_VER 
                           FROM TAB_COLUMNS
                           WHERE VERSION = 604)
     高效
          SELECT TAB_NAME
          FROM TABLES
          WHERE  (TAB_NAME,DB_VER)
 = ( SELECT TAB_NAME,DB_VER) 
                   FROM TAB_COLUMNS
                   WHERE VERSION = 604)
     Update 多個Column 例子:
     低效:
           UPDATE EMP
           SET EMP_CAT = (SELECT MAX(CATEGORY) FROM EMP_CATEGORIES),
              SAL_RANGE = (SELECT MAX(SAL_RANGE) FROM EMP_CATEGORIES)
           WHERE EMP_DEPT = 0020;
     高效:
           UPDATE EMP
           SET (EMP_CAT, SAL_RANGE) 
= (SELECT MAX(CATEGORY) , MAX(SAL_RANGE)
 FROM EMP_CATEGORIES)
           WHERE EMP_DEPT = 0020;
11. 在Oracle快速進行資料行存在性檢查
只檢索一個啟示就可以判斷主鍵是否能與外鍵相配,這比Count(*)方法快得多,例如: 
SQL Using Count(*) 
    SELECT Count(*) INTO :ll_Count
       FROM ORDER
       WHERE PROD_ID = :ls_CheckProd
       USING SQLCA;
    
    IF ll_Count > 0 THEN // Cannot delete product 
SQL Using ROWNUM
   SELECT ORDER_ID INTO :ll_OrderID
       FROM ORDER
       WHERE PROD_ID = :ls_CheckProd
          AND ROWNUM < 2
       USING SQLCA;

    IF SQLCA.SQLNRows <> 0 THEN // cannot delete product
12 使用%TYPE、%ROWTYPE方式聲明變數
  程式設計中常常要通過變數來實現程式間的資料傳遞,即將表中資料賦值給變數,或是把變數值插入到表中。而要完成這些操作的前提就是,表中資料與變數類型要一致。然而在實際中,表中資料或類型、或寬度有時要變化,一旦變化,就必須去修改程式中的變數聲明部分,否則程式將不能正常運行。為了減少這部分程式的修改,編程時使用%TYPE、%ROWTYPE方式聲明變數,使變數聲明的類型與表中的保持同步,隨表的變化而變化,這樣的程式在一定程度上具有更強的通用性。
13.       使用DECODE函數來減少處理時間
使用DECODE函數可以避免重複掃描相同記錄或重複串連相同的表.
例如:
   SELECT COUNT(*),SUM(SAL)
   FROM EMP
   WHERE DEPT_NO = 0020
   AND ENAME LIKE ‘SMITH%’;

   SELECT COUNT(*),SUM(SAL)
   FROM EMP
   WHERE DEPT_NO = 0030
   AND ENAME LIKE ‘SMITH%’;

你可以用DECODE函數高效地得到相同結果

SELECT COUNT(DECODE(DEPT_NO,0020,’X’,NULL)) D0020_COUNT,
        COUNT(DECODE(DEPT_NO,0030,’X’,NULL)) D0030_COUNT,
        SUM(DECODE(DEPT_NO,0020,SAL,NULL)) D0020_SAL,
        SUM(DECODE(DEPT_NO,0030,SAL,NULL)) D0030_SAL
FROM EMP WHERE ENAME LIKE ‘SMITH%’;

類似的,DECODE函數也可以運用於GROUP BY 和ORDER BY子句中.
14.       盡量多使用COMMIT
只要有可能,在程式中盡量多使用COMMIT, 這樣程式的效能得到提高,需求也會因為COMMIT所釋放的資源而減少:
 COMMIT所釋放的資源:
a.       復原段上用於恢複資料的資訊.
b.       被程式語句獲得的鎖
c.       redo log buffer 中的空間
d.       ORACLE為管理上述3種資源中的內部花費
15.       整合簡單,無關聯的資料庫訪問
如果你有幾個簡單的資料庫查詢語句,你可以把它們整合到一個查詢中(即使它們之間沒有關係)
例如:

SELECT NAME 
FROM EMP 
WHERE EMP_NO = 1234;

SELECT NAME 
FROM DPT
WHERE DPT_NO = 10 ;

SELECT NAME 
FROM CAT
WHERE CAT_TYPE = ‘RD’;

上面的3個查詢可以被合并成一個:

SELECT E.NAME , D.NAME , C.NAME
FROM CAT C , DPT D , EMP E,DUAL X
WHERE NVL(‘X’,X.DUMMY) = NVL(‘X’,E.ROWID(+))
AND NVL(‘X’,X.DUMMY) = NVL(‘X’,D.ROWID(+))
AND NVL(‘X’,X.DUMMY) = NVL(‘X’,C.ROWID(+))
AND E.EMP_NO(+) = 1234
AND D.DEPT_NO(+) = 10
AND C.CAT_TYPE(+) = ‘RD’; 
16.       WHERE子句中的串連順序.
ORACLE採用自下而上的順序解析WHERE子句,根據這個原理,表之間的串連必須寫在其他WHERE條件之前, 那些可以過濾掉最大數量記錄的條件必須寫在WHERE子句的末尾.
例如:
(低效,執行時間156.3秒)
SELECT … 
FROM EMP E
WHERE  SAL > 50000
AND    JOB = ‘MANAGER’
AND    25 < (SELECT COUNT(*) FROM EMP
             WHERE MGR=E.EMPNO);

(高效,執行時間10.6秒)
SELECT … 
FROM EMP E
WHERE 25 < (SELECT COUNT(*) FROM EMP
             WHERE MGR=E.EMPNO)
AND    SAL > 50000
AND    JOB = ‘MANAGER’;
17.     減少訪問資料庫的次數
當執行每條SQL語句時, ORACLE在內部執行了許多工作: 解析SQL語句, 估算索引的利用率, 綁定變數 , 讀資料區塊等等. 由此可見, 減少訪問資料庫的次數 , 就能實際上減少ORACLE的工作量.

例如,
    以下有三種方法可以檢索出僱員號等於0342或0291的職員.

方法1 (最低效)
    SELECT EMP_NAME , SALARY , GRADE
    FROM EMP 
    WHERE EMP_NO = 342;
     
    SELECT EMP_NAME , SALARY , GRADE
    FROM EMP 
    WHERE EMP_NO = 291;

方法2 (次低效)
    
    DECLARE 
        CURSOR C1 (E_NO NUMBER) IS 
        SELECT EMP_NAME,SALARY,GRADE
        FROM EMP 
        WHERE EMP_NO = E_NO;
    BEGIN 
        OPEN C1(342);
        FETCH C1 INTO …,..,.. ;
        …..
        OPEN C1(291);
       FETCH C1 INTO …,..,.. ;
         CLOSE C1;
      END;

方法3 (高效)

    SELECT A.EMP_NAME , A.SALARY , A.GRADE,
            B.EMP_NAME , B.SALARY , B.GRADE
    FROM EMP A,EMP B
    WHERE A.EMP_NO = 342
    AND   B.EMP_NO = 291; 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.