It's better to light a candle than to curse the darkness
-
老生常談的不要使用
select *
如果硬要使用select *,那麼就請忍受一下以下幾種可能會出現的問題
- select * 每次都把所有的欄位查詢出來,但並不是每個欄位都是必要的,會造成額外的傳輸頻寬資源,效能不可取
- 在完成分析之後,MySql會進行優化,也就是選擇執行效率最高的(Mysql自己認為的,但並不一定是最優),使用select * 會阻礙優化器選擇更優的執行計劃,比如走索引查詢
- 增加或刪除欄位的時候程式碼會出現問題,典型的就是如果新增一個新欄位,但是實體對映忘記新增,程式會出錯
-
僅查一條資料的時候,使用LIMIT 1
當某個業務你確信只會返回一行資料,就可以使用LIMIT 1來告訴執行引擎找到一行記錄後就停止下來,而不是繼續往下查下一條滿足的記錄,效能會好一點
-
使用union all替代union
union all 和 union的區別在於前者不會對資料進行去重,後者會去重,所以如果確信業務中不會存在重複的記錄值,使用union all效率會更高
-
where後面儘量不要使用or來連線查詢條件
如果硬要使用or,那麼就代表你要放棄走索引,選擇全表掃描
⭐可以採用union all
-
⚠️where後面謹慎使用in/not in,like
使用in、not in、like,其實還是會有走索引的時候的
in、not in在數量不多的時候,索引級別會去到range,一旦超出數量,索引也是會失效的,採用全表掃描
like只有一種情況會走索引,那就是確定字首情況,如下例子就是確定字首是以abc開頭的
⭐可以使用exists來替換in,但是得視乎於場合;如果是一個連續的區間值,可以使用between and來替代in;
如果還是要做模糊索引,可以選擇建立fulltext索引,或者直接走其他高效方式,例如ES等
-
關於exists和in的選擇
exists是先遍歷外表,然後看外表中的記錄有沒有跟內表中的匹配,適合內表較大,外表較小的情況
in是先遍歷內表,然後將內表與外表做一個笛卡爾積,適合內表比較小的情況
-
聯合索引需要遵循最左匹配原則
索引可以是一個列欄位,也可以是多個列欄位組成的聯合索引,對於最左匹配原則,要從最左邊作為起點開始匹配,而後如果遇到範圍查詢就會停止匹配,所以如果建立一個索引值為(a,b,c,d),那麼where後面的條件必須是以a開頭才能確保能走索引,如果其中c是一個範圍查詢(>, <, between, like),那麼後續的d就走不到索引了
-
優先考慮在where 以及 order by 涉及的列上建立索引
索引區分度公式:$count(distinct(col)) / count(*)$,表示欄位不重複的比率,比率越高,掃描的記錄就會越少,效率自然也就越高
where後面接的是條件查詢,order by是做分組,是做索引的好時機
-
索引列要保持乾淨,一定不能參與計算和使用函式,否則索引會失效
且看例子,索引有效
使用了substring函式操作索引列,索引失效
相似的還有,四則運算也會使得索引失效
-
能使用覆蓋索引就使用覆蓋索引
得先了解,聚簇索引和非聚簇索引這倆概念
聚簇索引:以主鍵建立的索引,葉子節點上存放的直接就是資料
非聚簇索引:非主鍵建立的索引,葉子節點上存的是主鍵+索引列,查詢的時候先取得主鍵,然後通過主鍵去查,所以也稱為二級索引,而拿到主鍵回查這個動作叫做回表
而如果查詢的列恰好是非聚簇索引的列,那麼就不需要回表操作了,因為回表還需要操作一次,效率肯定是比不上不回表的,而該非聚簇索引也被稱為覆蓋索引
-
join聯表查詢不要太多
這裡面的不要太多,究竟如何定義,阿里巴巴Java開發手冊(泰山版)是這麼描述的
而從另外一篇部落格上面,MySql建議join聯表查詢最大不要超過7
我個人的理解就是,join聯表個數太多肯定是會影響效率的,如果真的有業務需要如此操作,不妨先考察一下是不是業務設計上出現了問題,然後再優化聯表查詢,實在是需要的,也要像阿里巴巴開發手冊說的,做好索引,測試好SQL的效能
-
聯表查詢要關注表之間的字符集是否一致
字符集不一致的,join的時候索引會失效,之前就發現過開發環境跟生產環境不一致的情況,這個真的得review好
-
如果有需要到一批資料的插入或者更新,請使用批量操作,不要一條一條的操作
最後,歡迎關注微信公眾號【碼農Amg】,更多精彩乾貨盡在於此,獨樂樂不如眾樂樂(多人~學習?)