書(shū)寫(xiě)高質(zhì)量SQL的建議
1、避免混亂的邏輯
反例:(統(tǒng)計(jì)用戶數(shù)量)
- List<User> users = userMapper.selectAll();
- return users.size();
正例:
- int count = userMapper.countUser("select count(*) from user");
- return count;
2、select one 如果已知結(jié)果只有一條, 使用limit 1
反例:(查找nickname = 報(bào)之瓊瑤 的用戶)
- select id, nickname from t where nickname = '報(bào)之瓊瑤'
正例:
- select id, nickname from t where nickname = '報(bào)之瓊瑤' limit 1
理由:
- 加上limit1,只要找到了對(duì)應(yīng)的一條記錄, 就不會(huì)繼續(xù)向下掃描了,效率會(huì)大大提高。limit1適用于查詢結(jié)果為1條(也可能為0)會(huì)導(dǎo)致全表掃描的的SQL語(yǔ)句。
- 如果條件列上有索引就不用limit 1,如主鍵查詢 id = 1
3、盡量避免在where子句中使用or來(lái)連接條件
反例:(查找name = 張三 或者 法外狂徒 的用戶)
- select id,name from t where name = '張三' or name = '法外狂徒'
正例:
- select id,name from t where name = '張三'
- union all
- select id,name from t where name = '法外狂徒'
理由:
使用or將導(dǎo)致引擎放棄使用索引而進(jìn)行全表掃描
4、優(yōu)化like關(guān)鍵字
like常用于模糊查詢, 不恰當(dāng)?shù)木幋a會(huì)導(dǎo)致索引失效
反例:
- select userId,name from user where userId like '%123'
正例:
- select userId,name from user where userId like '123%'

%123, 百分號(hào)在前不走索引

123%,百分號(hào)在后走索引
但是也會(huì)存在百分號(hào)在后不走索引的情況,mysql的innodb存儲(chǔ)引擎最終執(zhí)行哪種方法都是基于成本計(jì)算的, 通過(guò)比較全表掃描和二級(jí)索引比較再回表查詢
可以通過(guò)
INFORMATION_SCHEMA.OPTIMIZER_TRACE來(lái)分析查詢過(guò)程

trace字段json復(fù)制出來(lái)即可分析
5、查詢SQL盡量不要使用select *,而是select具體字段, 不要返回用不到的任何字段。
反例:(統(tǒng)計(jì)用戶數(shù)量)
- select * from t
正例:
- select id, name, tel from t
理由:
- 妨礙優(yōu)化器選擇更優(yōu)的執(zhí)行計(jì)劃,比如說(shuō)索引掃描
- 增刪字段可能導(dǎo)致代碼崩潰
6、盡量避免在索引列上使用mysql的內(nèi)置函數(shù)
反例:
- select * from user where date_add(create_time,Interval 5 day) >=now()
正例:
- select * from user where create_time >= date_add(now(), interval - 5 day)

不走索引

走索引
7、應(yīng)盡量避免在 where 子句中對(duì)字段進(jìn)行表達(dá)式操作,這將導(dǎo)致系統(tǒng)放棄使用索引而進(jìn)行全表掃
反例: (對(duì)字段user_age進(jìn)行運(yùn)算操作, 不走索引)
- select * from user where user_age - 1 = 2
正例: (走索引)
- select * from user where user_age = 3