ORACLE優化SQL語句
阿新 • • 發佈:2019-02-04
換工作剛剛入職,公司要求學習這片文章。覺得挺給力,分享給各位網友。共同學習,共同進步吧!
(基礎表driving table)將被最先處理,在FROM 子句中包含多個表的情況下,你必須選擇記
錄條數最少的表作為基礎表。如果有3個以上的表連線查詢, 那就需要選擇交叉表(intersec
tion table)作為基礎表, 交叉表是指那個被其他表所引用的表.
RE 條件之前, 那些可以過濾掉最大數量記錄的條件必須寫在WHERE 子句的末尾.
完成的, 這意味著將耗費更多的時間
等;
關係)
DELETE FROM EMP E WHERE E.ROWID > (SELECT MIN(X.ROWID)
FROM EMP X WHERE X.EMP_NO = E.EMP_NO);
的資訊. 如果你沒有COMMIT 事務,ORACLE 會將資料恢復到刪除之前的狀態(準確地說是恢復
到執行刪除命令之前的狀況) 而當運用TRUNCATE 時, 回滾段不再存放任何可被恢復的資訊.
當命令執行後,資料不能被恢復.因此很少的資源被呼叫,執行時間也會很短. (譯者按: TRU
NCATE 只在刪除全表適用,TRUNCATE 是DDL 不是DML)
所釋放的資源而減少:
COMMIT 所釋放的資源:
a. 回滾段上用於恢復資料的資訊.
b. 被程式語句獲得的鎖
c. redo log buffer 中的空間
d. ORACLE 為管理上述3種資源中的內部花費
理需要排序,總計等操作. 如果能通過WHERE 子句限制記錄的數目,那就能減少這方面的開
銷. (非oracle 中)on、where、having 這三個都可以加條件的子句中,on 是最先執行,whe
re 次之,having 最後,因為on 是先把不符合條件的記錄過濾後才進行統計,它就可以減少
中間運算要處理的資料,按理說應該速度是最快的, where 也應該比having 快點的,因為
它過濾資料後才進行sum,在兩個表聯接時才用on 的,所以在一個表的時候,就剩下where
跟having 比較了。在這單表查詢統計的情況下,如果要過濾的條件沒有涉及到要計算欄位,
那它們的結果是一樣的,只是where 可以使用rushmore 技術,而having 就不能,在速度上
後者要慢如果要涉及到計算的欄位,就表示在沒計算之前,這個欄位的值是不確定的,根據
上篇寫的工作流程,where 的作用時間是在計算之前就完成的,而having 就是在計算後才
起作用的,所以在這種情況下,兩者的結果會不同。在多表聯接查詢時, on 比where 更早
起作用。系統首先根據各個表之間的聯接條件,把多個表合成一個臨時表後,再由where
進行過濾,然後再計算,計算完後再由having 進行過濾。由此可見,要想過濾條件起到正
確的作用,首先要明白這個條件應該在什麼時候起作用,然後再決定放在那裡
SELECT TAB_NAME FROM TABLES WHERE (TAB_NAME,DB_VER) = ( SELECT
TAB_NAME,DB_VER FROM TAB_COLUMNS WHERE VERSION = 604)
是非常有意義的
就可以減少解析的時間並減少那些由Column 歧義引起的語法錯誤.
下, 使用EXISTS(或NOT EXISTS)通常將提高查詢的效率. 在子查詢中,NOT IN 子句將執行
一個內部的排序和合並. 無論在哪種情況下,NOT IN 都是最低效的(因為它對子查詢中的
表執行了一個全表遍歷). 為了避免使用NOT IN ,我們可以把它改寫成外連線(Outer Join
s)或NOT EXISTS.
例子:
(高效)SELECT * FROM EMP (基礎表) WHERE EMPNO > 0 AND EXISTS (SELECT ‘X'
FROM DEPT WHERE DEPT.DEPTNO = EMP.DEPTNO AND LOC = ‘MELB')
(低效)SELECT * FROM EMP (基礎表) WHERE EMPNO > 0 AND DEPTNO IN(SELECT DEP
TNO FROM DEPT WHERE LOC = ‘MELB')
終是一個最好的方法:
SELECT EXECUTIONS , DISK_READS, BUFFER_GETS,
ROUND((BUFFER_GETS-DISK_READS)/BUFFER_GETS,2) Hit_radio,
ROUND(DISK_READS/EXECUTIONS,2) Reads_per_run,
SQL_TEXT
FROM V$SQLAREA
WHERE EXECUTIONS>0
AND BUFFER_GETS > 0
AND (BUFFER_GETS-DISK_READS)/BUFFER_GETS < 0.8
ORDER BY 4 DESC;
ee 結構. 通常,通過索引查詢資料比全表掃描要快. 當ORACLE 找出執行查詢和Update 語句
的最佳路徑時, ORACLE 優化器將使用索引. 同樣在聯結多個表時使用索引也可以提高效率.
另一個使用索引的好處是,它提供了主鍵(primary key)的唯一性驗證.。那些LONG 或LONG
RAW 資料型別, 你可以索引幾乎所有的列. 通常, 在大型表中使用索引特別有效. 當然,
你也會發現, 在掃描小表時,使用索引同樣能提高效率. 雖然使用索引能得到查詢效率的提
高,但是我們也必須注意到它的代價. 索引需要空間來儲存,也需要定期維護, 每當有記錄
在表中增減或索引列被修改時, 索引本身也會被修改. 這意味著每條記錄的INSERT , DEL
ETE , UPDATE 將為此多付出4 , 5 次的磁碟I/O . 因為索引需要額外的儲存空間和處理,
那些不必要的索引反而會使查詢反應時間變慢.。定期的重構索引是有必要的.:
ALTER INDEX <INDEXNAME> REBUILD <TABLESPACENAME>
ISTINCT. 一般可以考慮用EXIST 替換, EXISTS 使查詢更為迅速,因為RDBMS 核心模組將在
子查詢的條件一旦滿足後,立刻返回結果. 例子:
(低效):
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);
LE”遇到”NOT,他就會停止使用索引轉而執行全表掃描.
舉例:
低效:
SELECT … FROM DEPT WHERE SAL * 12 > 25000;
高效:
SELECT … FROM DEPT WHERE SAL > 25000/12;
SELECT * FROM EMP WHERE DEPTNO >=4
低效:
SELECT * FROM EMP WHERE DEPTNO >3
兩者的區別在於, 前者DBMS 將直接跳到第一個DEPT 等於4的記錄而後者將首先定位到DEPT
NO=3的記錄並且向前掃描到第一個DEPT 大於3的記錄.
成全表掃描. 注意, 以上規則只針對多個索引列有效. 如果有column 沒有被索引, 查詢效
率可能會因為你沒有選擇OR 而降低. 在下面的例子中, LOC_ID 和REGION 上都建有索引.
高效:
SELECT LOC_ID , LOC_DESC , REGION
FROM LOCATION
WHERE LOC_ID = 10
UNION
SELECT LOC_ID , LOC_DESC , REGION
FROM LOCATION
WHERE REGION = “MELBOURNE”
低效:
SELECT LOC_ID , LOC_DESC , REGION
FROM LOCATION
WHERE LOC_ID = 10 OR REGION = “MELBOURNE”
如果你堅持要用OR, 那就需要返回記錄最少的索引列寫在最前面.
徑似乎是相同的.
低效:
SELECT…. FROM LOCATION WHERE LOC_ID = 10 OR LOC_ID = 20 OR LOC_ID = 30
高效
SELECT… FROM LOCATION WHERE LOC_IN IN (10,20,30);
包含空值,索引中將不存在此記錄. 對於複合索引,如果每個列都為空,索引中同樣不存在
此記錄. 如果至少有一個列不為空,則記錄存在於索引中.舉例: 如果唯一性索引建立在
表的A 列和B 列上, 並且表中存在一條記錄的A,B 值為(123,null) , ORACLE 將不接受下一
條具有相同A,B 值(123,null)的記錄(插入). 然而如果所有的索引列都為空,ORACLE 將
認為整個鍵值為空而空不等於空. 因此你可以插入1000 條具有相同鍵值的記錄,當然它們
都是空! 因為空值不存在於索引列中,所以WHERE 子句中對索引列進行空值比較將使ORACLE
停用該索引.
低效: (索引失效)
SELECT … FROM DEPARTMENT WHERE DEPT_CODE IS NOT NULL;
高效: (索引有效)
SELECT … FROM DEPARTMENT WHERE DEPT_CODE >=0;
優化器才會選擇使用該索引. 這也是一條簡單而重要的規則,當僅引用索引的第二個列時,
優化器使用了全表掃描而忽略了索引
28) 用UNION-ALL 替換UNION ( 如果有可能的話):
當SQL 語句需要UNION 兩個查詢結果集合時,這兩個結果集合會以UNION-ALL 的方式被合
並, 然後在輸出最終結果前進行排序. 如果用UNION ALL 替代UNION, 這樣排序就不是必要
了. 效率就會因此得到提高. 需要注意的是,UNION ALL 將重複輸出兩個結果集合中相同記
錄. 因此各位還是要從業務需求分析使用UNION ALL 的可行性. UNION 將對結果集合排序,
這個操作會使用到SORT_AREA_SIZE 這塊記憶體. 對於這塊記憶體的優化也是相當重要的. 下面
的SQL 可以用來查詢排序的消耗量
低效:
SELECT ACCT_NUM, BALANCE_AMT
FROM DEBIT_TRANSACTIONS
WHERE TRAN_DATE = '31-DEC-95'
UNION
SELECT ACCT_NUM, BALANCE_AMT
FROM DEBIT_TRANSACTIONS
WHERE TRAN_DATE = '31-DEC-95'
高效:
SELECT ACCT_NUM, BALANCE_AMT
FROM DEBIT_TRANSACTIONS
WHERE TRAN_DATE = '31-DEC-95'
UNION ALL
SELECT ACCT_NUM, BALANCE_AMT
FROM DEBIT_TRANSACTIONS
WHERE TRAN_DATE = '31-DEC-95'
ORDER BY 中所有的列必須包含在相同的索引中並保持在索引中的排列順序.
ORDER BY 中所有的列必須定義為非空.
WHERE 子句使用的索引和ORDER BY 子句中所使用的索引不能並列.
例如:
表DEPT 包含以下列:
DEPT_CODE PK NOT NULL
DEPT_DESC NOT NULL
DEPT_TYPE NULL
低效: (索引不被使用)
SELECT DEPT_CODE FROM DEPT ORDER BY DEPT_TYPE
高效: (使用索引)
SELECT DEPT_CODE FROM DEPT WHERE DEPT_TYPE > 0
假設EMPNO 是一個數值型別的索引列.
SELECT … FROM EMP WHERE EMPNO = ‘123'
實際上,經過ORACLE 型別轉換, 語句轉化為:
SELECT … FROM EMP WHERE EMPNO = TO_NUMBER(‘123')
幸運的是,型別轉換沒有發生在索引列上,索引的用途沒有被改變.
現在,假設EMP_TYPE 是一個字元型別的索引列.
SELECT … FROM EMP WHERE EMP_TYPE = 123
這個語句被ORACLE 轉換為:
SELECT … FROM EMP WHERETO_NUMBER(EMP_TYPE)=123
因為內部發生的型別轉換, 這個索引將不會被用到! 為了避免ORACLE 對你的SQL 進行隱式
的型別轉換, 最好把型別轉換用顯式表現出來. 注意當字元和數值比較時, ORACLE 會優先
轉換數值型別到字元型別
情況下,使用索引比全表掃描要塊幾倍乃至幾千倍!
執行耗費資源的排序(SORT)功能. DISTINCT 需要一次排序操作, 而其他的至少需要執行兩
次排序. 通常, 帶有UNION, MINUS , INTERSECT 的SQL 語句都可以用其他方式重寫. 如果
你的資料庫的SORT_AREA_SIZE 調配得好, 使用UNION , MINUS, INTERSECT 也是可以考慮
的, 畢竟它們的可讀性很強
查詢返回相同結果但第二個明顯就快了許多.
低效:
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'
(1) 選擇最有效率的表名順序(只在基於規則的優化器中有效):
ORACLE 的解析器按照從右到左的順序處理FROM 子句中的表名,FROM 子句中寫在最後的表(基礎表driving table)將被最先處理,在FROM 子句中包含多個表的情況下,你必須選擇記
錄條數最少的表作為基礎表。如果有3個以上的表連線查詢, 那就需要選擇交叉表(intersec
tion table)作為基礎表, 交叉表是指那個被其他表所引用的表.
(2) WHERE 子句中的連線順序.:
ORACLE 採用自下而上的順序解析WHERE 子句,根據這個原理,表之間的連線必須寫在其他WHERE 條件之前, 那些可以過濾掉最大數量記錄的條件必須寫在WHERE 子句的末尾.
(3) SELECT 子句中避免使用‘ * ‘:
ORACLE 在解析的過程中, 會將'*' 依次轉換成所有的列名, 這個工作是通過查詢資料字典完成的, 這意味著將耗費更多的時間
(4) 減少訪問資料庫的次數:
ORACLE 在內部執行了許多工作: 解析SQL 語句, 估算索引的利用率, 繫結變數, 讀資料塊等;
(5) 在SQL*Plus , SQL*Forms 和Pro*C 中重新設定ARRAYSIZE 引數, 可以增加每次
資料庫訪問的檢索資料量,建議值為200(6) 使用DECODE 函式來減少處理時間:
使用DECODE 函式可以避免重複掃描相同記錄或重複連線相同的表.(7) 整合簡單,無關聯的資料庫訪問:
如果你有幾個簡單的資料庫查詢語句,你可以把它們整合到一個查詢中(即使它們之間沒有關係)
(8) 刪除重複記錄:
最高效的刪除重複記錄方法( 因為使用了ROWID)例子:DELETE FROM EMP E WHERE E.ROWID > (SELECT MIN(X.ROWID)
FROM EMP X WHERE X.EMP_NO = E.EMP_NO);
(9) 用TRUNCATE 替代DELETE:
當刪除表中的記錄時,在通常情況下, 回滾段(rollback segments ) 用來存放可以被恢復的資訊. 如果你沒有COMMIT 事務,ORACLE 會將資料恢復到刪除之前的狀態(準確地說是恢復
到執行刪除命令之前的狀況) 而當運用TRUNCATE 時, 回滾段不再存放任何可被恢復的資訊.
當命令執行後,資料不能被恢復.因此很少的資源被呼叫,執行時間也會很短. (譯者按: TRU
NCATE 只在刪除全表適用,TRUNCATE 是DDL 不是DML)
(10) 儘量多使用COMMIT:
只要有可能,在程式中儘量多使用COMMIT, 這樣程式的效能得到提高,需求也會因為COMMIT所釋放的資源而減少:
COMMIT 所釋放的資源:
a. 回滾段上用於恢復資料的資訊.
b. 被程式語句獲得的鎖
c. redo log buffer 中的空間
d. ORACLE 為管理上述3種資源中的內部花費
(11) 用Where 子句替換HAVING 子句:
避免使用HAVING 子句, HAVING 只會在檢索出所有記錄之後才對結果集進行過濾. 這個處理需要排序,總計等操作. 如果能通過WHERE 子句限制記錄的數目,那就能減少這方面的開
銷. (非oracle 中)on、where、having 這三個都可以加條件的子句中,on 是最先執行,whe
re 次之,having 最後,因為on 是先把不符合條件的記錄過濾後才進行統計,它就可以減少
中間運算要處理的資料,按理說應該速度是最快的, where 也應該比having 快點的,因為
它過濾資料後才進行sum,在兩個表聯接時才用on 的,所以在一個表的時候,就剩下where
跟having 比較了。在這單表查詢統計的情況下,如果要過濾的條件沒有涉及到要計算欄位,
那它們的結果是一樣的,只是where 可以使用rushmore 技術,而having 就不能,在速度上
後者要慢如果要涉及到計算的欄位,就表示在沒計算之前,這個欄位的值是不確定的,根據
上篇寫的工作流程,where 的作用時間是在計算之前就完成的,而having 就是在計算後才
起作用的,所以在這種情況下,兩者的結果會不同。在多表聯接查詢時, on 比where 更早
起作用。系統首先根據各個表之間的聯接條件,把多個表合成一個臨時表後,再由where
進行過濾,然後再計算,計算完後再由having 進行過濾。由此可見,要想過濾條件起到正
確的作用,首先要明白這個條件應該在什麼時候起作用,然後再決定放在那裡
(12) 減少對錶的查詢:
在含有子查詢的SQL 語句中,要特別注意減少對錶的查詢.例子:SELECT TAB_NAME FROM TABLES WHERE (TAB_NAME,DB_VER) = ( SELECT
TAB_NAME,DB_VER FROM TAB_COLUMNS WHERE VERSION = 604)
(13) 通過內部函式提高SQL 效率.:
複雜的SQL 往往犧牲了執行效率. 能夠掌握上面的運用函式解決問題的方法在實際工作中是非常有意義的
(14) 使用表的別名(Alias):
當在SQL 語句中連線多個表時, 請使用表的別名並把別名字首於每個Column 上.這樣一來,就可以減少解析的時間並減少那些由Column 歧義引起的語法錯誤.
(15) 用EXISTS 替代IN、用NOT EXISTS 替代NOT IN:
在許多基於基礎表的查詢中,為了滿足一個條件,往往需要對另一個表進行聯接.在這種情況下, 使用EXISTS(或NOT EXISTS)通常將提高查詢的效率. 在子查詢中,NOT IN 子句將執行
一個內部的排序和合並. 無論在哪種情況下,NOT IN 都是最低效的(因為它對子查詢中的
表執行了一個全表遍歷). 為了避免使用NOT IN ,我們可以把它改寫成外連線(Outer Join
s)或NOT EXISTS.
例子:
(高效)SELECT * FROM EMP (基礎表) WHERE EMPNO > 0 AND EXISTS (SELECT ‘X'
FROM DEPT WHERE DEPT.DEPTNO = EMP.DEPTNO AND LOC = ‘MELB')
(低效)SELECT * FROM EMP (基礎表) WHERE EMPNO > 0 AND DEPTNO IN(SELECT DEP
TNO FROM DEPT WHERE LOC = ‘MELB')
(16) 識別'低效執行'的SQL 語句:
雖然目前各種關於SQL 優化的圖形化工具層出不窮,但是寫出自己的SQL 工具來解決問題始終是一個最好的方法:
SELECT EXECUTIONS , DISK_READS, BUFFER_GETS,
ROUND((BUFFER_GETS-DISK_READS)/BUFFER_GETS,2) Hit_radio,
ROUND(DISK_READS/EXECUTIONS,2) Reads_per_run,
SQL_TEXT
FROM V$SQLAREA
WHERE EXECUTIONS>0
AND BUFFER_GETS > 0
AND (BUFFER_GETS-DISK_READS)/BUFFER_GETS < 0.8
ORDER BY 4 DESC;
17) 用索引提高效率:
索引是表的一個概念部分,用來提高檢索資料的效率,ORACLE 使用了一個複雜的自平衡B-tree 結構. 通常,通過索引查詢資料比全表掃描要快. 當ORACLE 找出執行查詢和Update 語句
的最佳路徑時, ORACLE 優化器將使用索引. 同樣在聯結多個表時使用索引也可以提高效率.
另一個使用索引的好處是,它提供了主鍵(primary key)的唯一性驗證.。那些LONG 或LONG
RAW 資料型別, 你可以索引幾乎所有的列. 通常, 在大型表中使用索引特別有效. 當然,
你也會發現, 在掃描小表時,使用索引同樣能提高效率. 雖然使用索引能得到查詢效率的提
高,但是我們也必須注意到它的代價. 索引需要空間來儲存,也需要定期維護, 每當有記錄
在表中增減或索引列被修改時, 索引本身也會被修改. 這意味著每條記錄的INSERT , DEL
ETE , UPDATE 將為此多付出4 , 5 次的磁碟I/O . 因為索引需要額外的儲存空間和處理,
那些不必要的索引反而會使查詢反應時間變慢.。定期的重構索引是有必要的.:
ALTER INDEX <INDEXNAME> REBUILD <TABLESPACENAME>
18) 用EXISTS 替換DISTINCT:
當提交一個包含一對多表資訊(比如部門表和僱員表)的查詢時,避免在SELECT 子句中使用DISTINCT. 一般可以考慮用EXIST 替換, EXISTS 使查詢更為迅速,因為RDBMS 核心模組將在
子查詢的條件一旦滿足後,立刻返回結果. 例子:
(低效):
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);
(19) sql 語句用大寫的;
因為oracle 總是先解析sql 語句,把小寫的字母轉換成大寫的再執行
(20) 在java 程式碼中儘量少用連線符“+”連線字串!
(21) 避免在索引列上使用NOT 通常,
我們要避免在索引列上使用NOT, NOT 會產生在和在索引列上使用函式相同的影響. 當ORACLE”遇到”NOT,他就會停止使用索引轉而執行全表掃描.
(22) 避免在索引列上使用計算.
WHERE 子句中,如果索引列是函式的一部分.優化器將不使用索引而使用全表掃描.舉例:
低效:
SELECT … FROM DEPT WHERE SAL * 12 > 25000;
高效:
SELECT … FROM DEPT WHERE SAL > 25000/12;
(23) 用 >= 替代 >
高效:SELECT * FROM EMP WHERE DEPTNO >=4
低效:
SELECT * FROM EMP WHERE DEPTNO >3
兩者的區別在於, 前者DBMS 將直接跳到第一個DEPT 等於4的記錄而後者將首先定位到DEPT
NO=3的記錄並且向前掃描到第一個DEPT 大於3的記錄.
(24) 用UNION 替換OR (適用於索引列)
通常情況下, 用UNION 替換WHERE 子句中的OR 將會起到較好的效果. 對索引列使用OR 將造成全表掃描. 注意, 以上規則只針對多個索引列有效. 如果有column 沒有被索引, 查詢效
率可能會因為你沒有選擇OR 而降低. 在下面的例子中, LOC_ID 和REGION 上都建有索引.
高效:
SELECT LOC_ID , LOC_DESC , REGION
FROM LOCATION
WHERE LOC_ID = 10
UNION
SELECT LOC_ID , LOC_DESC , REGION
FROM LOCATION
WHERE REGION = “MELBOURNE”
低效:
SELECT LOC_ID , LOC_DESC , REGION
FROM LOCATION
WHERE LOC_ID = 10 OR REGION = “MELBOURNE”
如果你堅持要用OR, 那就需要返回記錄最少的索引列寫在最前面.
(25) 用IN 來替換OR
這是一條簡單易記的規則,但是實際的執行效果還須檢驗,在ORACLE8i 下,兩者的執行路徑似乎是相同的.
低效:
SELECT…. FROM LOCATION WHERE LOC_ID = 10 OR LOC_ID = 20 OR LOC_ID = 30
高效
SELECT… FROM LOCATION WHERE LOC_IN IN (10,20,30);
(26) 避免在索引列上使用IS NULL 和IS NOT NULL
避免在索引中使用任何可以為空的列,ORACLE 將無法使用該索引.對於單列索引,如果列包含空值,索引中將不存在此記錄. 對於複合索引,如果每個列都為空,索引中同樣不存在
此記錄. 如果至少有一個列不為空,則記錄存在於索引中.舉例: 如果唯一性索引建立在
表的A 列和B 列上, 並且表中存在一條記錄的A,B 值為(123,null) , ORACLE 將不接受下一
條具有相同A,B 值(123,null)的記錄(插入). 然而如果所有的索引列都為空,ORACLE 將
認為整個鍵值為空而空不等於空. 因此你可以插入1000 條具有相同鍵值的記錄,當然它們
都是空! 因為空值不存在於索引列中,所以WHERE 子句中對索引列進行空值比較將使ORACLE
停用該索引.
低效: (索引失效)
SELECT … FROM DEPARTMENT WHERE DEPT_CODE IS NOT NULL;
高效: (索引有效)
SELECT … FROM DEPARTMENT WHERE DEPT_CODE >=0;
(27) 總是使用索引的第一個列:
如果索引是建立在多個列上, 只有在它的第一個列(leading column)被where 子句引用時,優化器才會選擇使用該索引. 這也是一條簡單而重要的規則,當僅引用索引的第二個列時,
優化器使用了全表掃描而忽略了索引
28) 用UNION-ALL 替換UNION ( 如果有可能的話):
當SQL 語句需要UNION 兩個查詢結果集合時,這兩個結果集合會以UNION-ALL 的方式被合
並, 然後在輸出最終結果前進行排序. 如果用UNION ALL 替代UNION, 這樣排序就不是必要
了. 效率就會因此得到提高. 需要注意的是,UNION ALL 將重複輸出兩個結果集合中相同記
錄. 因此各位還是要從業務需求分析使用UNION ALL 的可行性. UNION 將對結果集合排序,
這個操作會使用到SORT_AREA_SIZE 這塊記憶體. 對於這塊記憶體的優化也是相當重要的. 下面
的SQL 可以用來查詢排序的消耗量
低效:
SELECT ACCT_NUM, BALANCE_AMT
FROM DEBIT_TRANSACTIONS
WHERE TRAN_DATE = '31-DEC-95'
UNION
SELECT ACCT_NUM, BALANCE_AMT
FROM DEBIT_TRANSACTIONS
WHERE TRAN_DATE = '31-DEC-95'
高效:
SELECT ACCT_NUM, BALANCE_AMT
FROM DEBIT_TRANSACTIONS
WHERE TRAN_DATE = '31-DEC-95'
UNION ALL
SELECT ACCT_NUM, BALANCE_AMT
FROM DEBIT_TRANSACTIONS
WHERE TRAN_DATE = '31-DEC-95'
(29) 用WHERE 替代ORDER BY:
ORDER BY 子句只在兩種嚴格的條件下使用索引.ORDER BY 中所有的列必須包含在相同的索引中並保持在索引中的排列順序.
ORDER BY 中所有的列必須定義為非空.
WHERE 子句使用的索引和ORDER BY 子句中所使用的索引不能並列.
例如:
表DEPT 包含以下列:
DEPT_CODE PK NOT NULL
DEPT_DESC NOT NULL
DEPT_TYPE NULL
低效: (索引不被使用)
SELECT DEPT_CODE FROM DEPT ORDER BY DEPT_TYPE
高效: (使用索引)
SELECT DEPT_CODE FROM DEPT WHERE DEPT_TYPE > 0
(30) 避免改變索引列的型別.:
當比較不同資料型別的資料時, ORACLE 自動對列進行簡單的型別轉換.假設EMPNO 是一個數值型別的索引列.
SELECT … FROM EMP WHERE EMPNO = ‘123'
實際上,經過ORACLE 型別轉換, 語句轉化為:
SELECT … FROM EMP WHERE EMPNO = TO_NUMBER(‘123')
幸運的是,型別轉換沒有發生在索引列上,索引的用途沒有被改變.
現在,假設EMP_TYPE 是一個字元型別的索引列.
SELECT … FROM EMP WHERE EMP_TYPE = 123
這個語句被ORACLE 轉換為:
SELECT … FROM EMP WHERETO_NUMBER(EMP_TYPE)=123
因為內部發生的型別轉換, 這個索引將不會被用到! 為了避免ORACLE 對你的SQL 進行隱式
的型別轉換, 最好把型別轉換用顯式表現出來. 注意當字元和數值比較時, ORACLE 會優先
轉換數值型別到字元型別
(31) 需要當心的WHERE 子句:
某些SELECT 語句中的WHERE 子句不使用索引. 這裡有一些例子.在下面的例子裡,
(1)‘!=' 將不使用索引. 記住, 索引只能告訴你什麼存在於表中, 而不能告訴你什麼不存在於表中.
(2) ‘||'是字元連線函式. 就象其他函式那樣, 停用了索引.
(3) ‘+'是數學函式. 就象其他數學函式那樣, 停用了索引. (4)相同的索引列不能互相比較,這將會啟用全表掃描.
(32) a. 如果檢索資料量超過30%的表中記錄數.使用索引將沒有顯著的效率提高.
b. 在特定情況下, 使用索引也許會比全表掃描慢, 但這是同一個數量級上的區別. 而通常情況下,使用索引比全表掃描要塊幾倍乃至幾千倍!
(33) 避免使用耗費資源的操作:
帶有DISTINCT,UNION,MINUS,INTERSECT,ORDER BY 的SQL 語句會啟動SQL 引擎執行耗費資源的排序(SORT)功能. DISTINCT 需要一次排序操作, 而其他的至少需要執行兩
次排序. 通常, 帶有UNION, MINUS , INTERSECT 的SQL 語句都可以用其他方式重寫. 如果
你的資料庫的SORT_AREA_SIZE 調配得好, 使用UNION , MINUS, INTERSECT 也是可以考慮
的, 畢竟它們的可讀性很強
(34) 優化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