由於SQL優化優化起來比較複雜,並且還受環境限制,在開發過程中,寫SQL必須遵循以下幾點原則: 1.Oracle 採用自下而上的順序解析WHERE子句,根據這個原理,表之間的連接必須寫在其他Where條件之前,那些可以過濾掉最大數量記錄的條件必須寫在Where子句的末尾. 2.Select 語句避免 ...
由於SQL優化優化起來比較複雜,並且還受環境限制,在開發過程中,寫SQL必須遵循以下幾點原則:
1.Oracle 採用自下而上的順序解析WHERE子句,根據這個原理,表之間的連接必須寫在其他Where條件之前,那些可以過濾掉最大數量記錄的條件必須寫在Where子句的末尾.
2.Select 語句避免使用 *
當在Select子句中列出所有的COLUMN時,使用動態SQL列引用 *是一個方便的方法.可是,這是一個非常低效的方法.實際上,Oracle在解析的過程中,會將 * 一次轉換成所有的列名,這個工作是通過查詢數據字典完成的,這意味著將耗費更多的時間.
3.使用表的別名
當在Sql語句中離間多個表時,請使用標的別名並把別名首碼每個Column上.這樣一來,就可以減少解析的時間並減少哪些由Column歧義引起的語法錯誤.
註:Column歧義是指由於Sql中不同的表具有相同的Column名,當SQL語句中出現這個Column時,Sql解析器無法判斷這個Column的歸屬.
OracleSql的優化原則:
儘量少用In操作符,基本上所有In操作都可以用Exists代替,用In寫出的Sql的優點是比較容易寫及清晰易懂,但是用In的Sql性能總是比較低的,從Oracle執行的步驟來分析用In的Sql與不用In的Sql有以下區別:
Oracle視圖將其轉換成多個表的連接,如果轉換不成功則先執行In裡面的子查詢,在查詢外層的表記錄,如果轉換成功則直接採用多個表的連接方式查詢.由此可見用In的Sql至少多了一個轉換的過程.一般的Sql都可以轉換成功,但對於含有分組統計等方面的Sql就不能轉換了.
Oralce在執行In子查詢時,首先執行子查詢,將查詢結果放入臨時表再執行住查詢.而Exist則是首先檢查主查詢,然後運行子查詢知道找到第一個匹配項.NotExists比Not In效率稍高.但具體在尋則IN或EXIST操作時,要根據主子表數據量大小來具體考慮.
推薦方案:在業務密集的SQL當中儘量不用IN操作符,不用NOT IN操作符,可以用NOT EXISTS或者外連接+替代
不用'<>'或者'!='操作符.對不等於操作符的處理會造成全表掃描,可以用'<'or'>'代替.
不等於操作符是永遠不會用到索引的,因策對它的處理會造成全表掃描。
推薦方案:
1)a<>0用 a>0 or a<0;
2)a<>''改為 a>''
where子句中出現IS NULL或者 IS NOT NULL時,ORACLE會停止使用索引而執行全表掃描.可以考慮在設計表時,對索引列設置為NOT NULL,這樣就可以用其他操作來取代判斷NULL的操作。
推薦方案:
1) a is not null 改為 a > 0 或者 a > '' 等
2)不允許欄位為空,而用一個卻省值代替空值.
3)建立點陣圖索引(有分區的表不能建,點陣圖索引比較難控制,如欄位值太多索引會使性能下降,多人更新操作會增加數據塊鎖的現象)
當通配符'%'或者'_'作為查詢字元串的第一個字元時,索引不會被使用.
對於有連接的列'||',最後一個連接列索引會無效.儘量避免連接,可以分開連接或者使用不作用在列上的函數替代.
如果索引不是基於函數的,那麼當在Where子句中對索引列使用函數時,索引不再起作用.
Where子句中避免在索引上使用計算,否則將導致索引失效而進行全表掃描.
對數據類型不同的列進行比較時,會使索引失效.
> 及 < 操作符(大於或小於操作符)
大於或小於操作符一般情況下是不用調整的,因為它有索引就會採用索引查找,但有的情況下可以對它進行優化,如一個表有100萬記錄,一個數值型欄位A, 30萬記錄的A=0,30萬記錄的A=1,39萬記錄的A=2,1萬記錄的A=3。那麼執行A>2與A>=3的效果就有很大的區別了,因為 A>2時ORACLE會先找出為2的記錄索引再進行比較,而A>=3時ORACLE則直接找到=3的記錄索引。
推薦方案:用“>=”替代“>”。
UNION操作符
UNION在進行錶鏈接後會篩選掉重覆的記錄,所以在錶鏈接後會對所產生的結果集進行排序運算,刪除重覆的記錄再返回結果。實際大部分應用中是不會產生重覆的記錄,最常見的是過程表與歷史表UNION。如:
select * from gc_dfys
union
select * from ls_jg_dfys
這個SQL在運行時先取出兩個表的結果,再用排序空間進行排序刪除重覆的記錄,最後返回結果集,如果表數據量大的話可能會導致用磁碟進行排序。
推薦方案:採用UNION ALL操作符替代UNION,因為UNION ALL操作只是簡單的將兩個結果合併後就返回。
select * from gc_dfys
union all
select * from ls_jg_dfys
LIKE操作符
LIKE 操作符可以應用通配符查詢,裡面的通配符組合可能達到幾乎是任意的查詢,但是如果用得不好則會產生性能上的問題,如LIKE ‘%5400%’ 這種查詢不會引用索引,而LIKE ‘X5400%’則會引用範圍索引。一個實際例子:用YW_YHJBQK表中營業編號後面的戶標識號可來查詢營業編號 YY_BH LIKE ‘%5400%’ 這個條件會產生全表掃描,如果改成YY_BH LIKE ’X5400%’ OR YY_BH LIKE ’B5400%’ 則會利用YY_BH的索引進行兩個範圍的查詢,性能肯定大大提高。
SQL書寫的影響(共用SQL語句可以提高操作效率)
同一功能同一性能不同寫法SQL的影響
如一個SQL在A程式員寫的為
Select * from zl_yhjbqk
B程式員寫的為
Select * from dlyx.zl_yhjbqk(帶表所有者的首碼)
C程式員寫的為
Select * from DLYX.ZLYHJBQK(大寫表名)
D程式員寫的為
Select * from DLYX.ZLYHJBQK(中間多了空格)
以上四個SQL在ORACLE分析整理之後產生的結果及執行的時間是一樣的,但是從ORACLE共用記憶體SGA的原理,可以得出ORACLE對每個SQL 都會對其進行一次分析,並且占用共用記憶體,如果將SQL的字元串及格式寫得完全相同則ORACLE只會分析一次,共用記憶體也只會留下一次的分析結果,這不僅可以減少分析SQL的時間,而且可以減少共用記憶體重覆的信息,ORACLE也可以準確統計SQL的執行頻率。
推薦方案:不同區域出現的相同的Sql語句,要保證查詢字元完全相同,以利用SGA共用池,防止相同的Sql語句被多次分析。
查詢表順序的影響
Oracle從右到左處理From子句中的表名,所以在From子句中包含多個表的情況下,將記錄最少的表放在最後。(只在採用RBO優化時有效).
在FROM後面的表中的列表順序會對SQL執行性能影響,在沒有索引及ORACLE沒有對錶進行統計分析的情況下ORACLE會按表出現的順序進行鏈接,由此因為表的順序不對會產生十分耗伺服器資源的數據交叉。(註:如果對錶進行了統計分析, ORACLE會自動先進小表的鏈接,再進行大表的鏈接)。
Order By語句中的非索引列會降低性能,可以通過添加索引的方式處理。嚴格控制在Order By語句中使用表達式
當在Sql語句中連接多個表時,使用表的別名,並將之作為每列的首碼。這樣可以減少解析時間
多利用內部函數提高Sql效率
對條件欄位的一些優化
採用函數處理的欄位不能利用索引,如
substr(hbs_bh,1,4)=’5400’,優化處理:hbs_bh like ‘5400%’
trunc(sk_rq)=trunc(sysdate), 優化處理:sk_rq>=trunc(sysdate) and sk_rq<trunc(sysdate+1)
進行了顯式或隱式的運算的欄位不能進行索引,如:
ss_df+20>50,優化處理:ss_df>30
‘X’||hbs_bh>’X5400021452’,優化處理:hbs_bh>’5400021542’
sk_rq+5=sysdate,優化處理:sk_rq=sysdate-5
hbs_bh=5401002554,優化處理:hbs_bh=’ 5401002554’,註:此條件對hbs_bh 進行隱式的to_number轉換,因為hbs_bh欄位是字元型。
條件內包括了多個本表的欄位運算時不能進行索引
ys_df>cx_df,無法進行優化
qc_bh||kh_bh=’5400250000’,優化處理:qc_bh=’5400’ and kh_bh=’250000’
可能引起全表掃描的操作
在索引列上使用NOT或者“<>”
對索引列使用函數或者計算
NOT IN操作
通配符位於查詢字元串的第一個字元
IS NULL或者IS NOT NULL
多列索引,但它的第一個列並沒有被Where子句引用