Mysql 的FIND_IN_SET函數慢的憂化


一個頁面的查詢,數據量不算太多,也不算太少,竟然用了10多秒

一、需求

    查找出卡片表里所包含的DIY卡片ID所對應的名字

 

二、sql 語句祥細信息

  SELECT cardName

     FROM diyCard

     WHERE FIND_IN_SET(id, ( SELECT group_concat(id) FROM card))

  diyCard表的數據量幾千,card表的數據量幾萬

  原本SQL並沒有這么少,這是分析后為了讓大家能夠更加明白的簡易代碼。

 

三、問題分析


  1)首先看一看索引加了沒,沒加,之后加了索引快了一些,但還是慢
  2)再觀察代碼
  最終把問題放在了FIND_IN_SET(id,(select group_concat(id) from card))
  仔細觀察這段代碼

  FIND_IN_SET是一個函數,里面的參數嵌套了一個子查詢,意思就是說每次查找card表是否有diycard的id都可能是又運行了一次(select group_concat(id) from card),所以導致慢的根本原因。

  怎么辦呢,想一想sql的執行順序:
  1).首先執行 FROM 子句,從diycard表組裝數據源(沒問題)
  2).執行where子句,執行函數FIND_IN_SET,參數的數據源是(select group_concat(id) from card),就像上面說的每次查找diycard的id循環遍歷都會運行(select group_concat(id) from card),在這里會消耗很多時間
  那么就從這里改造,把(select group_concat(id) from card)改成一個死數據一樣,不讓它每次去查數據庫。
  注意把(select group_concat(id) from card)加到from后面,執行sql時直接組裝數據源。還有這里的group_concat(id)讓這個數據源只有一條記錄,所以不會產生笛卡爾集。


四、解決問題
  

SELECT cardname
   FROM diycard, ( SELECT group_concat(id) id FROM card) temp
   WHERE
  FIND_IN_SET(id, temp.card)


憂化sql的方法有很多
  1).索引的添加
  2).對於長sql,先刪除部分不引響不慢的sql,再從剩余的sqll慢慢定位出效率低的sql
  3).多使用explain(可以幫助我們分析 select 語句,讓我們知道查詢效率低下的原因,從而改進我們查詢,讓查詢優化器能夠更好的工作。)  

  。。。。。

文章作者介紹:

 

來自於小豹科技的田時偉-公司專注於軟件基礎研發平台,目前公司正在研發一款基於Netty的插件式的API網關-小豹API網關。 希望與對OpenAPI、微服務、API網關、Service Mesh等感興趣的朋友多交流。 有興趣的朋友請加QQ群244054462。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM