一个页面的查询,数据量不算太多,也不算太少,竟然用了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。