為什么要對SQL優化:
1、執行性能低
2、等待時間過長
3、SQL寫的太差
4、索引失效
·····等等
SQL優化的一些方法:
1、EXPLAIN
做MySQL優化,我們要善用EXPLAIN查看SQL執行計划。
下面來個簡單的示例,標注(1、2、3、4、5)我們要重點關注的數據:

type列,連接類型。一個好的SQL語句至少要達到range級別。杜絕出現all級別。
key列,使用到的索引名。如果沒有選擇索引,值是NULL。
key_len列,索引長度。不損失精確性的情況下,長度越短越好
rows列,掃描行數。該值是個預估值。
extra列,詳細說明。注意,常見的不太友好的值,如下:Using filesort,Using temporary。
注:MySQL Explain詳解可以參考 https://www.cnblogs.com/leeego-123/p/11846613.html
2、區分in和exists
select * from 表A where id in (select id from 表B)
用下面的語句替換:
select * from 表A where exists(select * from 表B where 表B.id=表A.id)
區分in和exists主要是造成了驅動順序的改變(這是性能變化的關鍵)。
如果是exists,那么以外層表為驅動表,先被訪問;
如果是IN,那么先執行子查詢。
所以IN適合於外表大而內表小的情況;EXISTS適合於外表小而內表大的情況。
3、避免在where子句中對字段進行null值判斷
對於null的判斷會導致引擎放棄使用索引而進行全表掃描。
可以在num上設置默認值0,確保表中num列沒有null值,然后這樣查詢:
select id from t where num=0
4、in 和 not in 也要慎用,否則會導致全表掃描
如:
select id from t where num in(1,2,3)
對於連續的數值,能用 between 就不要用 in 了:
select id from t where num between 1 and 3
5、避免在where子句中對字段進行表達式操作
比如下面的SQL中對字段就行了算術運算,這會造成引擎放棄使用索引,
select user_id,user_project from user_base where age*2=36;
建議改成:
select user_id,user_project from user_base where age=36/2;
再比如
select id from t where num/2=100
應改為:
select id from t where num=100*2
6、應盡量避免在 where 子句中使用!=或<>操作符,否則將引擎放棄使用索引而進行全表掃描
7、應盡量避免在where子句中對字段進行函數操作,這將導致引擎放棄使用索引而進行全表掃描
select id from t where substring(name,1,3)='abc'; --name以abc開頭的id
應改為:
select id from t where name like 'abc%'
8、避免隱式類型轉換
隱式轉換導致索引失效.這一點應當引起重視.也是開發中經常會犯的錯誤.
由於表的字段tu_mdn定義為varchar2(20),但在查詢時把該字段作為number類型以where條件傳給Oracle,這樣會導致索引失效.
錯誤的例子:
select * from test where tu_mdn=13333333333;
正確的例子:
select * from test where tu_mdn='13333333333';
9、對於聯合索引(組合索引)來說,要遵守最左前綴法則
可以參考這兩篇博客——
https://w.cnblogs.com/rocker-pg/p/11635414.html
https://www.cnblogs.com/hongmoshui/p/10429842.html
10、任何地方都不要使用 select * from t ,用具體的字段列表代替“*”,不要返回用不到的任何字段。
SELECT*增加很多不必要的消耗(CPU、IO、內存、網絡帶寬);
增加了使用覆蓋索引的可能性;
當表結構發生改變時,前斷也需要更新。
所以要求直接在select后面接上字段名。
11、如果排序字段沒有用到索引,就盡量少排序
12、如果限制條件中其他字段沒有索引,盡量少用or
or兩邊的字段中,如果有一個不是索引字段,而其他條件也不是索引字段,會造成該查詢不走索引的情況。
很多時候使用union all或者是union(必要的時候)的方式來代替“or”會得到更好的效果。
select id from t where num=10 or num=20
可以這樣查詢:
select id from t where num=10
union all
select id from t where num=20
13、盡量用union all代替union
union和union all的差異主要是前者需要將結果集合並后再進行唯一性過濾操作,這就會涉及到排序,增加大量的CPU運算,加大資源消耗及延遲。
當然,union all的前提條件是兩個結果集沒有重復數據。
14、不建議使用%前綴模糊查詢
例如LIKE“%name”或者LIKE“%name%”,這種查詢會導致索引失效而進行全表掃描。但是可以使用LIKE “name%”。
假如有這樣一列code的值為'AAA','AAB','BAA','BAB' ,如果where code like '%AB'條件
由於前面是模糊的,所以不能利用索引的順序,必須一個個去找,看是否滿足條件。這樣會導致全索引掃描或者全表掃描。
如果是這樣的條件where code like 'A % ',就可以查找CODE中A開頭的CODE的位置,
當碰到B開頭的數據時,就可以停止查找了,因為后面的數據一定不滿足要求。這樣就可以利用索引了。
15、索引數量不要過多
索引並不是越多越好,索引固然可以提高相應的 select 的效率,但同時也降低了 insert 及 update 的效率,
因為 insert 或 update 時有可能會重建索引,所以怎樣建索引需要慎重考慮,視具體情況而定。
一個表的索引數最好不要超過6個,若太多則應考慮一些不常使用到的列上建的索引是否有必要。