1,or请使用union all代替;
2,with...as...尽量使用交叉查询来替代,必要时也可以使用join代替;
3,in请使用exists代替;
4,时间上用>= and <=请使用between代替;
5,适当情况下增加trunk函数:
6,若用IN (SELECT ...)本身就會自動distinct了…語法中也不需要寫distinct…
7,在寫sql的where condition 時不要對column用function
(如下原语句和优化后的语句对比:
原语句:
AND (TO_DATE(WORK_DATE,'YYYY-MM-DD') BETWEEN NVL(:start_date, TO_DATE('2000-01-01','YYYY-MM-DD'))
AND NVL(:end_date, TO_DATE('2222-01-01','YYYY-MM-DD')))
优化后语句:
work_date between to_char(NVL(:start_date, TO_DATE('2000-01-01','YYYY-MM-DD')),'YYYY-MM-DD')
AND to_char(NVL(:end_date, TO_DATE('2222-01-01','YYYY-MM-DD'))),'YYYY-MM-DD')"
**Trunk的使用方法:
使用where to_date(to_char(a.in_process_time,'YYYY-MM-DD'),'YYYY-MM-DD') between :sdate and :edate的這種寫法是不會使用index的,因此我加了and a.in_process_time between trunc(:sdate) and trunc(:edate) + 0.99999進去做有效的table access
寫sql的原則 :
(1) column = value ,不使用function在column上
例1:
WORK_DATE||LPAD(TO_CHAR(WORK_TIME),2,'0')>='2010101200'
AND
WORK_DATE||LPAD(TO_CHAR(WORK_TIME),2,'0')<='2010101223'
這樣子寫不會使用index,可加入一個條件(access key),讓資料先縮小輸出的筆數
,再由原條件來filter,也就是改寫為以下寫法
WORK_DATE||LPAD(TO_CHAR(WORK_TIME),2,'0')>='2010101200'
AND
WORK_DATE||LPAD(TO_CHAR(WORK_TIME),2,'0')<='2010101223'
AND WORK_DATE BETWEEN '1010101200' AND '1010101223'
例2:
substr(abc,1,6) = 'avcdefg'
可改寫為
abc like 'avcdefg%'
(2) 減少使用in-List,可試著用exists或join的方式改寫
如果是not in則可用not exists來改寫
(3) or 有時不會使用index,可試著用union 或union all改寫
(4) 當查詢的資料量為總共資料的百分之四至五,才會用到index,所以若欄位中的值都一樣,或變異不大
建index不會被使用。
(5) 若資料分佈不均,則不要使用變數來當filter條件,這個道理我先前講過了,所以不再重覆說明。
有興趣的話可以上網查:column histrogram與bind varable peeking
此外…with … as …的語法,是用在一段需要大量sorting的sql,重覆被使用時再來使用,否則效果不會好到哪裡去
且反而會更慢
来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/23307206/viewspace-1043069/,如需转载,请注明出处,否则将追究法律责任。
转载于:http://blog.itpub.net/23307206/viewspace-1043069/