ORACLE SQL性能優化系列 (十一)
2024-08-29 13:46:45
供稿:網友
Oracle SQL性能優化系列 (十一)
36. 用UNION替換OR (適用于索引列) 通常情況下, 用UNION替換WHERE子句中的OR將會起到較好的效果. 對索引列使用OR將造成全表掃描. 注重, 以上規則只針對多個索引列有效. 假如有column沒有被索引, 查詢效率可能會因為你沒有選擇OR而降低. 在下面的例子中, LOC_ID 和REGION上都建有索引.高效:SELECT LOC_ID , LOC_DESC , REGIONFROM LOCATIONWHERE LOC_ID = 10UNIONSELECT LOC_ID , LOC_DESC , REGIONFROM LOCATIONWHERE REGION = “MELBOURNE” 低效:SELECT LOC_ID , LOC_DESC , REGIONFROM LOCATIONWHERE LOC_ID = 10 OR REGION = “MELBOURNE” 假如你堅持要用OR, 那就需要返回記錄最少的索引列寫在最前面. 注重: WHERE KEY1 = 10 (返回最少記錄)OR KEY2 = 20 (返回最多記錄) ORACLE 內部將以上轉換為WHERE KEY1 = 10 AND((NOT KEY1 = 10) AND KEY2 = 20) 譯者按: 下面的測試數據僅供參考: (a = 1003 返回一條記錄 , b = 1 返回1003條記錄)SQL> select * from unionvsor /*1st test*/2 where a = 1003 or b = 1;1003 rows selected.Execution Plan----------------------------------------------------------0 SELECT STATEMENT Optimizer=CHOOSE1 0 CONCATENATION2 1 TABLE access (BY INDEX ROWID) OF 'UNIONVSOR'3 2 INDEX (RANGE SCAN) OF 'UB' (NON-UNIQUE)4 1 TABLE ACCESS (BY INDEX ROWID) OF 'UNIONVSOR'5 4 INDEX (RANGE SCAN) OF 'UA' (NON-UNIQUE)Statistics----------------------------------------------------------0 recursive calls0 db block gets144 consistent gets0 physical reads0 redo size63749 bytes sent via SQL*Net to client7751 bytes received via SQL*Net from client68 SQL*Net roundtrips to/from client0 sorts (memory)0 sorts (disk)1003 rows PRocessedSQL> select * from unionvsor /*2nd test*/2 where b = 1 or a = 1003 ; 1003 rows selected.Execution Plan----------------------------------------------------------0 SELECT STATEMENT Optimizer=CHOOSE1 0 CONCATENATION2 1 TABLE ACCESS (BY INDEX ROWID) OF 'UNIONVSOR'3 2 INDEX (RANGE SCAN) OF 'UA' (NON-UNIQUE)4 1 TABLE ACCESS (BY INDEX ROWID) OF 'UNIONVSOR'5 4 INDEX (RANGE SCAN) OF 'UB' (NON-UNIQUE)Statistics----------------------------------------------------------0 recursive calls0 db block gets143 consistent gets0 physical reads0 redo size63749 bytes sent via SQL*Net to client7751 bytes received via SQL*Net from client
68 SQL*Net roundtrips to/from client0 sorts (memory)0 sorts (disk)1003 rows processed SQL> select * from unionvsor /*3rd test*/2 where a = 10033 union 4 select * from unionvsor5 where b = 1;1003 rows selected.Execution Plan----------------------------------------------------------0 SELECT STATEMENT Optimizer=CHOOSE1 0 SORT (UNIQUE)2 1 UNION-ALL3 2 TABLE ACCESS (BY INDEX ROWID) OF 'UNIONVSOR'4 3 INDEX (RANGE SCAN) OF 'UA' (NON-UNIQUE)5 2 TABLE ACCESS (BY INDEX ROWID) OF 'UNIONVSOR'6 5 INDEX (RANGE SCAN) OF 'UB' (NON-UNIQUE)Statistics----------------------------------------------------------0 recursive calls0 db block gets10 consistent gets 0 physical reads0 redo size63735 bytes sent via SQL*Net to client7751 bytes received via SQL*Net from client68 SQL*Net roundtrips to/from client1 sorts (memory)0 sorts (disk)1003 rows processed用UNION的效果可以從consistent gets和 SQL*NET的數據交換量的減少看出 37. 用IN來替換OR 下面的查詢可以被更有效率的語句替換: 低效: SELECT….FROM LOCATIONWHERE LOC_ID = 10OR LOC_ID = 20OR LOC_ID = 30 高效SELECT…FROM LOCATIONWHERE LOC_IN IN (10,20,30); 譯者按:這是一條簡單易記的規則,但是實際的執行效果還須檢驗,在ORACLE8i下,兩者的執行路徑似乎是相同的. 38. 避免在索引列上使用IS NULL和IS NOT NULL避免在索引中使用任何可以為空的列,ORACLE將無法使用該索引 .對于單列索引,假如列包含空值,索引中將不存在此記錄. 對于復合索引,假如每個列都為空,索引中同樣不存在此記錄. 假如至少有一個列不為空,則記錄存在于索引中.舉例:假如唯一性索引建立在表的A列和B列上, 并且表中存在一條記錄的A,B值為(123,null) , ORACLE將不接受下一條具有相同A,B值(123,null)的記錄(插入). 然而假如所有的索引列都為空,ORACLE將認為整個鍵值為空而空不等于空. 因此你可以插入1000條具有相同鍵值的記錄,當然它們都是空! 因為空值不存在于索引列中,所以WHERE子句中對索引列進行空值比較將使ORACLE停用該索引.舉例: 低效: (索引失效)SELECT …FROM DEPARTMENTWHERE DEPT_CODE IS NOT NULL; 高效: (索引有效)SELECT …FROM DEPARTMENTWHERE DEPT_CODE >=0;