ORACLE SQL性能優化系列 (十三)

ORACLE SQL性能優化系列 (十三)

作者: black_snail
 

關鍵字 ORACLE PERFORMANCE TUNING PL/SQL 

出處 http://www.dbasupport.com 

43. 用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 

非唯一性的索引(DEPT_TYPE) 

低效: (索引不被使用) 
SELECT DEPT_CODE 
FROM DEPT 
ORDER BY DEPT_TYPE 

EXPLAIN PLAN: 
SORT ORDER BY 
TABLE ACCESS FULL 


高效: (使用索引) 
SELECT DEPT_CODE 
FROM DEPT 
WHERE DEPT_TYPE > 0 

EXPLAIN PLAN: 
TABLE ACCESS BY ROWID ON EMP 
INDEX RANGE SCAN ON DEPT_IDX 

譯者按: 

ORDER BY 也能使用索引! 這的確是個容易被忽視的知識點. 我們來驗證一下: 

SQL> select * from emp order by empno; 

Execution Plan 

---------------------------------------------------------- 

 SELECT STATEMENT Optimizer=CHOOSE 

 0 TABLE ACCESS (BY INDEX ROWID) OF 'EMP' 

 1 INDEX (FULL SCAN) OF 'EMPNO' (UNIQUE) 



44. 避免改變索引列的類型. 

當比較不同數據類型的數據時, 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 
WHERE TO_NUMBER(EMP_TYPE)=123 

因爲內部發生的類型轉換, 這個索引將不會被用到! 

譯者按: 

爲了避免ORACLE對你的SQL進行隱式的類型轉換, 最好把類型轉換用顯式表現出來. 注意當字符和數值比較時, ORACLE會優先轉換數值類型到字符類型. 


45. 需要當心的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'; /*將使用索引*/ 

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