一個頁面的查詢,數據量不算太多,也不算太少,竟然用了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。