前言
今天生产环境又出现sql连接超时了,这个sql里面用了in,in后面的数据多的时候有几百个。我和同事还有技术经理初步确定了两个原因引起的超时,第一 技术经理说in 后面的长度太长了有两三百个了,第二 我和同事说怎么感觉是人大金仓的问题呢,国产数据库问题就是多。实际上都没找到问题的关键。
请一定要把问题排查看完,有惊喜
原sql,SQL_ONE (ps:SQL_ONE,这个简称就代表原链接超时的sql,下文就用这个简称)
-- 字段和表名非实际字段
SELECT dept_id, count(id) AS total
FROM "member"
WHERE del = 0 AND status = 3
AND active_status = 1
AND dept_id IN (
222726,222546,222562,222727,222722,222694,222633,222859,222854,222622,222822,222552,222567,
2057 95,205794,205782,205782,222848,222830,222602,225806,222780,222823,222857,222670,222672,222779,
205692,222632,222722,222540,222680,222582,222682,205692,222858,222573,222656,222673,222677,
222579,205773,222577,222669,222683,222679,222668,222570,222655,222572,222602,222666,222592,222688,222590,222585,222672,222569,222756,205775,222829,205702,222674,222676,222675,222583,222654
,222729,222587,222548.......)
GROUP BY dept_id ;
问题排查
我们拥有20开发经验的技术经理说,in里面直接用子查询吧
调整后的sql,SQL_TWO** (ps:SQL_TWO ,这个简称就代表调整后的sql)
-- 字段和表名非实际字段
SELECT dept_id, count(id) AS total
FROM "member"
WHERE del = 0 AND status = 3
AND active_status = 1
AND dept_id IN ( SELECT id FROM "dept" WHERE "path" LIKE '10799.%' AND "type" = 7 )
GROUP BY dept_id ;
SELECT id FROM "dept" WHERE "path" LIKE '10799.%' AND "type" = 7 查询结果等同原sql in 里面的参数。
我草这不得更慢了吗,现在sql不得先执行子查询然后再执行分组统计,这不得查询得更久????????*
然后小杨,就直接打开Navicat连接生产数据执行了一下,我草还真的变快了!!!!!!!!!
ps:看到这儿有人知道为什么吗?本着摸鱼人的精神,我在下班前一个小时就开始分析了
sql 执行计划分析
现在就分析一下SQL_ONE 和 SQL_TWO 为何执行时间和我们预期的不一样?
下面我从两个方面来分析,第一执行时间,第二执行计划(ps:下面打码的是真实字段,用dept_id和dept表代替)
SQL_ONE 执行时间 28s,执行计划如下
全表扫描,最后发现原来member中的dept_id 是varchar,而SQL_ONE中的参数是数字
SQL_TWO 执行时间4.5s,执行计划如下
SQL_TWO中的子查询SELECT id FROM "dept" WHERE "path" LIKE '10799.%' AND "type" = 7查询的结果id是bigint 类型和member中dept_id类型也对不上,但是看执行计划好像把member中的dept_id转成了Bigint,好像还是走了索引的。
博主知识有限,就理解成,SQL的优化器通过什么手段优化了吧。
SQL_THREE 这个SQL,我们就测试没有类型转换的情况。
-- 把in中的参数加上引号
SELECT dept_id, count(id) AS total
FROM "member"
WHERE del = 0 AND status = 3
AND active_status = 1
AND dept_id IN (
'222726','222546','222562',.......)
GROUP BY dept_id ;
执行时间60毫秒,执行计划
https://p6-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/0e82a19dacbe4dccbd7a436572e4f992~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg5o-Q5YmN6YCA5LyR5LqG:q75.awebp?rk3s=f64ab15b&x-expires=1729227648&x-signature=%2B%2Bn8F0P8Q4rX0%2BnG21%2Fi%2FZIIajA%3D
没有类型转换,没有子查询,直接index scan索引扫描,这才是正确的解法!!!!
总结
当sql查询缓慢,当执行不及预期,我们还是要使用explain去分析呀!!!
看起来把一个sql分成两段,每个分段的执行时间一定小于整个sql,经过我们测试不是的,在有索引并且类型不一致的情况下面,sql有你意想不到的执行思路。比如 SQL_ONE 的执行时间就远大于 SQL_TWO 的执行时间