1、SQL編寫注意事項
1.1 null 列
null 列使用索引是無意義的,任何包含null 值的列都不會包含在索引中。因此where 語句中的is null 或者 is not null 的語句,導致索引失效。
1.2 concat 或 ||
concate 或 || 是mysql 和 oracle 的字符串連接操作,如果對列進行函數操作,就會忽略索引的使用,比如下面的查詢語句:
-- 忽律索引 select ... from .. where first_name || '' || last_name = 'bill gates' ; -- 使用索引 select ... from .. where first_name = 'bill' and last_name = 'bill gates' ;
1.3 like
使用like進行模糊查詢時,如果通配符%在首位則索引會失效,如下sql語句:
-- 無法使用索引 select .. from .. where name like'%t%' -- 可以使用索引 select .. from .. where name like 't%' ;
1.4 order by
order by 子句中不要使用非索引列或嵌套表達式,這樣都會導致性能降低。
1.5 使用 !=或<> 操作會使索引失效
-- 索引無效 select .. from .. where sal != 3000 ; select .. from .. where sal <>3000 ;
1.6 使用 or 需要注意
1、or兩邊的字段中,如果有一個不是索引字段,而其他條件也不是索引字段,會造成該查詢不走索引的情況。很多時候使用union all或者是union(必要的時候)的方式來代替“or”會得到更好的效果。
2、如果or 兩邊字段都有索引,用explain 也可能出現索引失效的情況
對於使用or導致索引失效的情況
select id from t where c1=1 or c2=2 改為 select id from t where c1=1 UNION ALL select id from t where c2=2
1.7 where 和 having
select .. from .. on .. where .. group by .. having .. order by .. limit ..,以上是sql語句的語法結構,其中on、where和having是有過濾行為的,過濾行為越能提前完成就越可以減少傳遞給下一個階段的數據量,因此如果在having中的過濾行為能夠在where中完成,則應該優先考慮where來實現。
1.8 exists 和 in 的選擇
select * from 表A where id in (select id from 表B) 相當於 select * from 表A where id exits(select id from 表B where 表B.id =表A.id)
在選擇使用exits 和 in 的原則根據驅動順序的進行選擇,如果是exists,那么以外層表為驅動表,先被訪問,如果是IN,那么先執行子查詢。所以
1、當A表數據量大,B表數據量小情況下使用IN
2、當B表數據量大,A表數據量小使用exitsts
關於not in和not exists,推薦使用not exists,不僅僅是效率問題,not in可能存在邏輯問題。如何高效的寫出一個替代not exists的SQL語句?
select colname … from A表 where a.id not in (select b.id from B表) 修改為: select colname … from A表 left join B 表 where a.id=b.id and b.id is null
1.9 where 后面的‘=‘后面使用函數、算術運算或其他表達式運算,系統將可能無法正確使用索引
select id from t where num/2=100 可以更改為 select id from t where num=100*2 (該方法索引不失效) select id from t where substring(name,1,3)='abc' 可以更改 select id from t where name like "abc%"
1.10 避免對where 后面的字段進行隱私類型轉換
where子句中出現column字段的類型和傳入的參數類型不一致的時候發生的類型轉換,建議先確定where中的參數類型。
select name from t where int(age)=20 對字段進行了類型轉換,索引失效
1.11 對於聯合索引注意最左法則
舉列來說索引含有字段id、name、school,可以直接用id字段,也可以id、name這樣的順序,但是name;school都無法使用這個索引。所以在創建聯合索引的時候一定要注意索引字段順序,常用的查詢字段放在最前面。
1.12 注意范圍查詢 between > <
使用范圍查詢會使范圍查詢后面的索引失效
1.13 對於join的優化
LEFT JOIN A表為驅動表,INNER JOIN MySQL會自動找出那個數據少的表作用驅動表,RIGHT JOIN B表為驅動表。
1)mysql 每有fulljoin
select * from A left join B on B.name = A.name where B.name is null union allselect * from B;
2)盡量使用inner join,避免left join:
參與聯合查詢的表至少為2張表,一般都存在大小之分。如果連接方式是inner join,在沒有其他過濾條件的情況下MySQL會自動選擇小表作為驅動表,但是left join在驅動表的選擇上遵循的是左邊驅動右邊的原則,即left join左邊的表名為驅動表。
3)合理利用索引:
被驅動表的索引字段作為on的限制字段。
4)利用小表去驅動大表:
5)巧用STRAIGHT_JOIN:
inner join是由MySQL選擇驅動表,但是有些特殊情況需要選擇另個表作為驅動表,比如有group by、order by等「Using filesort」、「Using temporary」時。STRAIGHT_JOIN來強制連接順序,在STRAIGHT_JOIN左邊的表名就是驅動表,右邊則是被驅動表。在使用STRAIGHT_JOIN有個前提條件是該查詢是內連接,也就是inner join。其他鏈接不推薦使用STRAIGHT_JOIN,否則可能造成查詢結果不准確。