優化總結之sql優化(一)

一、SQL語句執行步驟

1、語法分析
2、語義分析
3、視圖轉換
4、表達式轉換

5、選擇優化器

6、選擇連接方式

7、選擇連接順序

8、選擇數據的搜索路徑

9、運行“執行計劃”

二、選用適合的Oracle優化器

RULE(基於規則)
COST(基於成本)

CHOOSE(選擇性)

三、訪問Table的方式

1、全表掃描 

全表掃描就是順序地訪問表中每條記錄,ORACLE採用一次讀入多個數據塊(database block)的方式優化全表掃描

2、通過ROWID訪問表

ROWID包含了表中記錄的物理位置信息,ORACLE採用索引實現了數據和存放數據的物理位置(ROWID)之間的聯繫,通常索引提供了快速訪問ROWID的方法,因此那些基於索引列的查詢就可以得到性能上的提高

四、共享 SQL 語句

1、Oracle提供對執行過的SQL語句進行高速緩衝的機制。被解析過並且確定了執行路徑的SQL語句存放在SGA的共享池中。

2、Oracle執行一個SQL語句之前每次先從SGA共享池中查找是否有緩衝的SQL語句,如果有則直接執行該SQL語句。

3、可以通過適當調整SGA共享池大小來達到提高Oracle執行性能的目的。

五、訪問順序

1、選擇最有效率的表名順序(1)

ORACLE的解析器按照從右到左的順序處理FROM子句中的表名,因此FROM子句中寫在最後的表(基礎表 driving table)將被最先處理 

當ORACLE處理多個表時,會運用排序及合併的方式連接它們。首先,掃描第一個表(FROM子句中最後的那個表)並對記錄進行派序,然後掃描第二個表(FROM子句中最後第二個表),最後將所有從第二個表中檢索出的記錄與第一個表中合適記錄進行合併.


只在基於規則的優化器中有效

2、選擇最有效率的表名順序(2)

    表 TAB1 16,384 條記錄

     表 TAB2 1      條記錄

    選擇TAB2作爲基礎表 (最好的方法)
     select count(*) from tab1,tab2   執行時間0.96秒
     
    選擇TAB2作爲基礎表 (不佳的方法)

     select count(*) from tab2,tab1   執行時間26.09秒

3、選擇最有效率的表名順序(3)

如果有3個以上的表連接查詢, 那就需要選擇交叉表(intersection table)作爲基礎表, 交叉表是指那個被其他表所引用的表.

SELECT * FROM LOCATION L, CATEGORY C, EMP E 
WHERE E.EMP_NO BETWEEN 1000 AND 2000
     AND E.CAT_NO = C.CAT_NO
     AND E.LOCN = L.LOCN
將比下列SQL更有效率
SELECT * FROM EMP E, LOCATION L, CATEGORY C
WHERE E.CAT_NO = C.CAT_NO
     AND E.LOCN = L.LOCN

     AND E.EMP_NO BETWEEN 1000 AND 2000

4、Where子句中的連接順序 (1)

Oracle採用自下而上的順序解析WHERE子句。
根據這個原理,表之間的連接必須寫在其他WHERE條件之前,那些可以過濾掉最大數量記錄的條件必須寫在WHERE子句的末尾。

5、Where子句中的連接順序 (2)

(低效,執行時間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’

六、SELECT子句中避免使用“*”

Oracle在解析SQL語句的時候,對於“*”將通過查詢數據庫字典來將其轉換成對應的列名。

如果在Select子句中需要列出所有的Column時,建議列出所有的Column名稱,而不是簡單的用“*”來替代,這樣可以減少多於的數據庫查詢開銷。

七、減少訪問數據庫的次數

當執行每條SQL語句時, ORACLE在內部執行了許多工作: 
解析SQL語句
估算索引的利用率
綁定變量 

讀數據塊等等

由此可見, 減少訪問數據庫的次數 , 就能實際上減少ORACLE的工作量.

七.1、整合簡單無關聯的數據庫訪問

如果有幾個簡單的數據庫查詢語句,你可以把它們整合到一個查詢中(即使它們之間沒有關係),以減少多於的數據庫IO開銷

注意:雖然採取這種方法,效率得到提高,但是程序的可讀性大大降低,所以還是要權衡之間的利弊 

八、使用Truncate而非Delete

Delete表中記錄的時候,Oracle會在Rollback段中保存刪除信息以備恢復。Truncate刪除表中記錄的時候不保存刪除信息,不能恢復。因此Truncate刪除記錄比Delete快,而且佔用資源少。


刪除表中記錄的時候,如果不需要恢復的情況之下應該儘量使用Truncate而不是Delete。


Truncate僅適用於刪除全表的記錄。

儘量多使用COMMIT

只要有可能,在程序中儘量多使用COMMIT, 這樣程序的性能得到提高,需求也會因爲COMMIT所釋放的資源而減少。

COMMIT所釋放的資源:
 回滾段上用於恢復數據的信息.
 被程序語句獲得的鎖
  redo log buffer 中的空間

  ORACLE爲管理上述3種資源中的內部花費

計算記錄條數

Select count(*) from tablename;

Select count(1) from tablename;

Select max(rownum) from tablename;

一般認爲,在沒有索引的情況之下,第一種方式最快。

如果有索引列,使用索引列當然最快。

用Where子句替換Having子句

避免使用HAVING子句,HAVING 只會在檢索出所有記錄之後纔對結果集進行過濾。這個處理需要排序、總計等操作。 如果能通過WHERE子句限制記錄的數目,就能減少這方面的開銷。

使用表的別名(Alias)

當在SQL語句中連接多個表時, 請使用表的別名並把別名前綴於每個Column上.這樣一來,就可以減少解析的時間並減少那些由Column歧義引起的語法錯誤

Column歧義指的是由於SQL中不同的表具有相同的Column名,當SQL語句中出現這個Column時,SQL解析器無法判斷這個Column的歸屬 

用EXISTS替代IN(1)

在許多基於基礎表的查詢中,爲了滿足一個條件 ,往往需要對另一個表進行聯接。在這種情況下,使用EXISTS(或NOT EXISTS)通常將提高查詢的效率

用EXISTS替代IN(2)

低效:
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 (1)

在子查詢中,NOT IN子句將執行一個內部的排序和合並,對子查詢中的表執行一個全表遍歷,因此是非常低效的。


 爲了避免使用NOT IN,可以把它改寫成外連接(Outer Joins)或者NOT EXISTS。

用NOT EXISTS替代NOT IN (2)

低效:
SELECT …
  FROM EMP
WHERE DEPT_NO NOT IN (SELECT DEPT_NO 
                                                FROM DEPT 

                                              WHERE 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’) 

用表連接替換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’ 

用EXISTS替換DISTINCT (1)

當提交一個包含對多表信息(比如部門表和僱員表)的查詢時,避免在SELECT子句中使用DISTINCT。 一般可以考慮用EXIST替換。

EXISTS 使查詢更爲迅速,因爲RDBMS核心模塊將在子查詢的條件一旦滿足後,立刻返回結果。

用EXISTS替換DISTINCT (2)

低效:
    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)

如何識別低效的SQL語句是我們sql調優的關鍵。

由於時間關係今天只寫到這,持續更新優化總結之sql優化(二)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章