SQL優化之操作符篇
2024-07-21 02:33:23
供稿:網友
今天霄漢的SQL優化培訓收獲頗豐,摘要出一部分. 1.1 IN 操作符 用IN寫出來的SQL的優點是比較輕易寫及清楚易懂,這比較適合現代軟件開發的風格。 但是用IN的SQL性能總是比較低的,從Oracle執行的步驟來分析用IN的SQL與不用IN的SQL有以下區別: ORACLE試圖將其轉換成多個表的連接,假如轉換不成功則先執行IN里面的子查詢,再查詢外層的表記錄,假如轉換成功則直接采用 多個表的連接方式查詢。 由此可見用IN的SQL至少多了一個轉換的過程。一般的SQL都可以轉換成功,但對于含有分組統計等方面的SQL就不能轉換了。 推薦方案:在業務密集的SQL當中盡量不采用IN操作符而使用EXISTS。 1.2 NOT IN操作符 此操作是強列推薦不使用的,因為它不能應用表的索引。 推薦方案:用NOT EXISTS代替 1.3 <> 操作符(不等于) 不等于操作符是永遠不會用到索引的,因此對它的處理只會產生全表掃描。 推薦方案:用其它相同功能的操作運算代替,如 a<>0 改為 a>0 or a<0
a<>’’ 改為 a>’’ 1.4 IS NULL 或IS NOT NULL操作(判定字段是否為空) 判定字段是否為空一般是不會應用索引的,因為B樹索引是不索引空值的。 推薦方案: 用其它相同功能的操作運算代替,如 a is not null 改為 a>0 或a>’’等。 不答應字段為空,而用一個缺省值代替空值。 1.5 > 及 < 操作符(大于或小于操作符) 大于或小于操作符一般情況下是不用調整的,因為它有索引就會采用索引查找,但有的情況下可以對它進行優化, 如一個表有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的記錄 索引。 1.6 LIKE操作符 LIKE操作符可以應用通配符查詢,里面的通配符組合可能達到幾乎是任意的查詢,但是假如用得不好則會產生性能上的問題, 如LIKE ‘%5400%’ 這種查詢不會引用索引,而LIKE ‘X5400%’則會引用范圍索引。 一個實際例子:用YW_YHJBQK表中營業編號后面的戶標識號可來查詢營業編號 YY_BH LIKE ‘%5400%’ 這個條件會產生全表掃描, 假如改成YY_BH LIKE ’X5400%’ OR YY_BH LIKE ’B5400%’ 則會利用YY_BH的索引進行兩個范圍的查詢,性能肯定大大提高。 1.7 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 1.8 group by用法 Oracle的GROUP BY語句除了最基本的語法外,還支持ROLLUP和CUBE語句。 select topicid,userid,sum(counter) from cis_topic_stat group by rollup(topicid,userid); 也就是說,假如是ROLLUP(A, B, C)的話,首先會對(A、B、C)進行GROUP BY,然后對(A、B)進行GROUP BY, 然后是(A)進行GROUP BY,最后對全表進行GROUP BY操作。 select topicid,userid,sum(counter) from cis_topic_stat group by cube(topicid,userid); 和ROLLUP相比,CUBE又增加了對STATUS列的GROUP BY統計。 假如是GROUP BY CUBE(A, B, C),則首先會對(A、B、C)進行GROUP BY,然后依次是(A、B),(A、C),(A),(B、C),(B),(C), 最后對全表進行GROUP BY操作。 1.9 如何使用Hint提示 在select/delete/update后寫/*+ hint */ 如 select /*+ index(TABLE_NAME INDEX_NAME) */ col1... 注重/*和+之間不能有空格 如用hint指定使用某個索引 select /*+ index(cbotab) */ col1 from cbotab;
select /*+ index(cbotab cbotab1) */ col1 from cbotab;
select /*+ index(a cbotab1) */ col1 from cbotab a; 其中 TABLE_NAME是必須要寫的,且假如在查詢中使用了表的別名,在hint也要用表的別名來代替表名; INDEX_NAME可以不必寫,Oracle會根據統計值選一個索引; 假如索引名或表名寫錯了,那這個hint就會被忽略;