likes
comments
collection
share

select in 的知识盲区前言 今天生产环境又出现sql连接超时了,这个sql里面用了in,in后面的数据多的时候有

作者站长头像
站长
· 阅读数 31

前言

今天生产环境又出现sql连接超时了,这个sql里面用了in,in后面的数据多的时候有几百个。我和同事还有技术经理初步确定了两个原因引起的超时,第一 技术经理说in 后面的长度太长了有两三百个了,第二 我和同事说怎么感觉是人大金仓的问题呢,国产数据库问题就是多。实际上都没找到问题的关键。

请一定要把问题排查看完,有惊喜

原sql,SQL_ONEps: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连接生产数据执行了一下,我草还真的变快了!!!!!!!!!!

select in 的知识盲区前言 今天生产环境又出现sql连接超时了,这个sql里面用了in,in后面的数据多的时候有

ps:看到这儿有人知道为什么吗?本着摸鱼人的精神,我在下班前一个小时就开始分析了

sql 执行计划分析

现在就分析一下SQL_ONESQL_TWO 为何执行时间和我们预期的不一样? 下面我从两个方面来分析,第一执行时间,第二执行计划(ps:下面打码的是真实字段,用dept_iddept表代替)

  • SQL_ONE 执行时间 28s,执行计划如下

select in 的知识盲区前言 今天生产环境又出现sql连接超时了,这个sql里面用了in,in后面的数据多的时候有

全表扫描,最后发现原来member中的dept_idvarchar,而SQL_ONE中的参数是数字

  • SQL_TWO 执行时间4.5s,执行计划如下

select in 的知识盲区前言 今天生产环境又出现sql连接超时了,这个sql里面用了in,in后面的数据多的时候有 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毫秒,执行计划

select in 的知识盲区前言 今天生产环境又出现sql连接超时了,这个sql里面用了in,in后面的数据多的时候有 没有类型转换,没有子查询,直接index scan索引扫描,这才是正确的解法!!!!

总结

  1. sql查询缓慢,当执行不及预期,我们还是要使用explain去分析呀!!!
  2. 看起来把一个sql分成两段,每个分段的执行时间一定小于整个sql,经过我们测试不是的,在有索引并且类型不一致的情况下面,sql有你意想不到的执行思路。比如 SQL_ONE 的执行时间就远大于 SQL_TWO 的执行时间
转载自:https://juejin.cn/post/7424009003920916490
评论
请登录