一、改寫in
在SQL語言中,一個查詢塊能夠做爲另外一個查詢塊中謂詞的一個操做數。所以,SQL查詢能夠層層嵌套。例如在一個大型分佈式數據庫系統中,有訂單表Order、訂單信息表OrderDetail,若是須要兩表關聯查詢:
SELECT CreateUser FROM Order WHERE OrderNo IN ( SELECT OrderNo FROM OrderDetail WHERE Price=0.5)
可替代方案:
SELECT CreateUser FROM Order,OrderDetail WHERE Order.OrderNo=OrderDetail.OrderNo AND Praice=0.5
一個列的標籤同時在主查詢和where子句中的查詢中出現,那麼極可能當主查詢中的列值改變以後,子查詢必須從新查詢一次。查詢嵌套層次越多,效率越低,
所以應當儘可能避免子查詢。若是子查詢不可避免,那麼要在子查詢中過濾掉儘量多的行。
2 、改寫LIKE
在SQL語句中,
LIKE關鍵字支持通配符匹配,但這種匹配特別耗費時間。
例如:SELECT * FROM Order WHERE CreateUser LIKE ‘M_ _ _’ 。即便在CreateUser字段上創建了索引,在這種狀況下也仍是採用順序掃描的方式,Order表中有1000條記錄,就須要比較1000次。
若是把語句改成SELECT * FROM Order WHERE CreateUser>= ’M’ AND CreateUser<’N’,在執行查詢時就會利用索引來查詢,顯然會大大提升速度。
三、改寫OR或<>
咱們在編寫sql時,一般都會按照程序邏輯去寫,此時,當咱們遇到以下場景: 我要查詢企業員工表(employee)中的員工狀態爲實習(type=’01’)或者兼職的全部員工(type=’08’),假設狀態共有10種 此時,咱們立馬會寫以下Sql:
Select * from employee A whereA.type=’01’ or A.type=’08’
咱們假設,在type列上存在索引。而此Sql含有or運算,對於優化器來講,由於沒法運用到一個範圍,因此沒法利用索引掃描。而一般此種狀況須要遍歷全部記錄或者全部索引。這樣會明顯提升查詢cost。咱們但願是經過索引的方式,畢竟該表是個大表,若是出現大表掃描,多系統性能有很大的影響。那麼能夠採起用UNION改寫OR子句,以下:
Select * from employee A whereA.type=’01’ union Select * from employee A whereA.type=’02
改寫成上述sql,優化器會分別執行兩個查詢子集,而後union合併。這樣就能夠利用到索引(type=‘01’)。固然Union包含去除重複元素的功能,即至關於distinct,這樣就會有排序存在,若是業務場景容許,能夠考慮使用union all,它和union不一樣的是,它無需排序去重,只須要兩個子集合並即刻。效率要高於union。
原則是: 當存在大表連接且鏈接條件較多,而且鏈接條件包含Or子句時,建議使用Union/Union all來替換。 對於不等與來講也是相似,不等於在邏輯上實際上是相似於 Not 的概念。
如,對以下sql:
Sql_stmt_2: Select * from employee where type !=’01’ 因此咱們能夠有以下改寫方式:
1) 將<>改寫爲Not in操做,即 Select * from employee where type not in (‘01’)
2) 將<>改寫爲大於和小於的結合 Select * from employee where type >’01’ union Select * from employee where type <’01’(固然若是你知道一個大於已經足夠,那麼徹底能夠省略掉小於的操做,這就是分析sql的業務場景)
顯然,對於1)的改法,它適用與Not in 子集中有多個值的狀況;對於2)改法,要要因爲1),由於它能夠利用到Type列上的索引。 原則是:
當存在大表連接且鏈接條件較多,而且鏈接條件包含不等於(<>||!=)子句時,建議使用Union/Union all 聯合大於小於操做來替換。
4 合理使用Notin和NotExists
雖然Notin和Notexits能夠實現相同的功能,可是二者自己的實現方式不一樣: NotIn:是自內向外操做,即先獲得子查詢結果,而後執行外層查詢。Notin子句的執行順序是:首先取外部一個查詢結果與內部子集比較,不論是否存在,它都要遍歷整個子集,每每沒法利用到索引,於是是由內向外過程。因此,當內部查詢子集很大時,就會具備較高的查詢代價。 NotExists:偏偏相反,是外向內操做。即先執行外部查詢結果,而後再執行內部操做,是集合操做。Notexists子句的執行順序是:首先取外部一個查詢結果與內部子集比較,若存在即刻返回,而不須要遍歷整個子集,若是存在索引,就會使用索引,於是是個自外而內的過程。因此,當內部子集很大時,相對來講,性能要優於Notin。 於是,總的來講,
Notexits在總體性能上要因爲Notin。
原則: 當子查詢結果集較大時,Notexists較Notin具備較高的性能提高; 當子查詢結果集較小時(個數或者百數之內),二者相差很少,通常來講,此時Notin會優於Notexists。就好像表數據小時,全表掃描老是要因爲索引掃描;
當子查詢具備必定的複雜度時(即sql關聯關係較多,如子查詢句中包含多個表查詢),因爲內部查詢的複雜度,會致使Notexists查詢具備較大的複雜度,下降性能。
此時能夠考慮採用Notin。 IN與Exists二者相差很少,這裏不作比較,思路相同。
5 避免使用distinct
使用distinct是爲了保證在結果集中不出現重複值,可是distinct會產生一張工做表,並進行排序來刪除重複記錄,這會大大增長查詢和I/O的操做次數。所以應當避免使用distinct關鍵字。
6 錶鏈接
錶鏈接有兩個要點:
1)錶鏈接順序 2)鏈接條件
Sql_stmt_1: Select * from A left join B on A.id=B.id join C on B.id = C.C_id where A.con=’ ’ and B.con=’ ’
通常狀況下,DB2會根據各表的JOIN順序自頂向下處理,即從Sql來看,就是自左向右解析,先A、B作鏈接操做,以後會產生結果集,將會寫入內存,若是內存不夠,會寫入臨時表空間,以後會用結果集和C作鏈接操做。若是sql中只有兩錶鏈接,那麼其先後順序沒什麼關係,優化器會本身去評估。而若是sql中存在超過2個錶鏈接時,那麼錶鏈接就會有順序之分。
那麼,
原則是: 若是sql中存在表A、B、C三表鏈接,則首先應保證最早鏈接的兩表具備較小的子集。 在進行錶鏈接時,須要提供鏈接字段(即On語法後的等價謂詞,on A.id=B.id)。此時,咱們須要保證,
鏈接字段存在索引。這樣當結果集小時,會走NestJoin(速度快,由於會利用到索引),當結果集大時,會走Hash join。此外,在對A、B表進行鏈接時,優化器須要判斷採用何種鏈接類型,這時會先執行where 字句後的條件。也就是說,
若是where字句能過濾不少的條件,那麼錶鏈接的結果集就會很小,cost天然會下降,因此適當爲where字句的查詢字段創建索引,可以獲得更好的性能。原則: 在進行錶鏈接時,爲鏈接字段和查詢過濾字段(where 字句後的條件)創建索引,會獲得很好的性能提高。
錶鏈接時鏈接字段只有一個會更好。