書寫高質量sql的一些建議

碼農Amg發表於2022-02-18

It's better to light a candle than to curse the darkness

  • 老生常談的不要使用select *

    如果硬要使用select *,那麼就請忍受一下以下幾種可能會出現的問題

    1. select * 每次都把所有的欄位查詢出來,但並不是每個欄位都是必要的,會造成額外的傳輸頻寬資源,效能不可取
    2. 在完成分析之後,MySql會進行優化,也就是選擇執行效率最高的(Mysql自己認為的,但並不一定是最優),使用select * 會阻礙優化器選擇更優的執行計劃,比如走索引查詢
    3. 增加或刪除欄位的時候程式碼會出現問題,典型的就是如果新增一個新欄位,但是實體對映忘記新增,程式會出錯
  • 僅查一條資料的時候,使用LIMIT 1

    當某個業務你確信只會返回一行資料,就可以使用LIMIT 1來告訴執行引擎找到一行記錄後就停止下來,而不是繼續往下查下一條滿足的記錄,效能會好一點

  • 使用union all替代union

    union all 和 union的區別在於前者不會對資料進行去重,後者會去重,所以如果確信業務中不會存在重複的記錄值,使用union all效率會更高

  • where後面儘量不要使用or來連線查詢條件

    如果硬要使用or,那麼就代表你要放棄走索引,選擇全表掃描

    ⭐可以採用union all

    image-20220217153010116

  • ⚠️where後面謹慎使用in/not in,like

    使用in、not in、like,其實還是會有走索引的時候的

    in、not in在數量不多的時候,索引級別會去到range,一旦超出數量,索引也是會失效的,採用全表掃描沒有超過個數情況超出個數情況

    like只有一種情況會走索引,那就是確定字首情況,如下例子就是確定字首是以abc開頭的image-20220217155534058

    ⭐可以使用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是做分組,是做索引的好時機

  • 索引列要保持乾淨,一定不能參與計算和使用函式,否則索引會失效

    且看例子,索引有效

    image-20220217212140361

    使用了substring函式操作索引列,索引失效

    image-20220217212244232

    相似的還有,四則運算也會使得索引失效

    image-20220217212709732

  • 能使用覆蓋索引就使用覆蓋索引

    得先了解,聚簇索引和非聚簇索引這倆概念

    聚簇索引:以主鍵建立的索引,葉子節點上存放的直接就是資料

    非聚簇索引:非主鍵建立的索引,葉子節點上存的是主鍵+索引列,查詢的時候先取得主鍵,然後通過主鍵去查,所以也稱為二級索引,而拿到主鍵回查這個動作叫做回表

    而如果查詢的列恰好是非聚簇索引的列,那麼就不需要回表操作了,因為回表還需要操作一次,效率肯定是比不上不回表的,而該非聚簇索引也被稱為覆蓋索引

  • join聯表查詢不要太多

    這裡面的不要太多,究竟如何定義,阿里巴巴Java開發手冊(泰山版)是這麼描述的

    image-20220217230021649

    而從另外一篇部落格上面,MySql建議join聯表查詢最大不要超過7

    傳送門

    我個人的理解就是,join聯表個數太多肯定是會影響效率的,如果真的有業務需要如此操作,不妨先考察一下是不是業務設計上出現了問題,然後再優化聯表查詢,實在是需要的,也要像阿里巴巴開發手冊說的,做好索引,測試好SQL的效能

  • 聯表查詢要關注表之間的字符集是否一致

    字符集不一致的,join的時候索引會失效,之前就發現過開發環境跟生產環境不一致的情況,這個真的得review好

  • 如果有需要到一批資料的插入或者更新,請使用批量操作,不要一條一條的操作

最後,歡迎關注微信公眾號【碼農Amg】,更多精彩乾貨盡在於此,獨樂樂不如眾樂樂(多人~學習?)

相關文章