mysql中更新语句中where子查询_记一次MySQL更新操作 where 子查询(in 子句)出现的性能坑!!!!...

由于这个问题纠缠了我一下午,现在记录一下,以免后续重覆辙!

场景简单描述大概是这样的,有两张表A(id,name,xxx),B(id,aid,name,xxx),其中B表的aid列是A表的外键,现在我想根据一些条件从B表选出aid然后根据这些aid对A表进行更新,其中A表的数据量大概是七百万条,B表的数据量是四五千条,刚开始我写的sql大概是这样子的:

UPDATE scene_info set onoff = -1

WHERE ID in(

select SCENEID from scene_operation tt left join global_dev_master_slave_ref ms

on ms.master_dev_id=tt.LINKERID and ms.slave_dev_id=tt.DEVID

where linkerid is not null

and isdisable = 0

and ms.master_dev_id is null

and ms.slave_dev_id is null);

理论上这点数据量应该很快就会执行完成,但是事实不是这样的,一直running,无语,多次直接杀掉执行进程分析,无果,各种加上索引后查看执行计划如图:

d445e53c9c1097c85ae03aac9714be7d.png

第一条对对主表的更新,走的是主键,但是看rows ,居然扫描了六百多万条记录,这个表总共的记录才七百多万,只过滤掉了100条数据,但是其实符合条件的记录只有几十条而已。

为什么会这样呢,上面的执行计划后两条的select type都是DEPENDENT SUBQUERY,这意味着什么?——子查询取决于外面的查询,MySql 先执行外查询,内查询根据这个查询结果(如执行计划里所述,6940599 rows)的每一条记录组成新的查询语句。

好坑,mysql内部居然这样执行,但是如果把整个更新语句改成查询语句,结果又大大不一样,查询结果出来的速度是毫秒级的。后面经过各种网上搜索找到解决方案,in子查询改为join联表更新,更改sql为如下样子:

update scene_info si inner join scene_operation so on si.id = so.SCENEID left join global_dev_master_slave_ref ms

on ms.master_dev_id=so.LINKERID and ms.slave_dev_id=so.DEVID set si.onoff = -1

where so.linkerid is not null

and so.isdisable = 0

and ms.master_dev_id is null

and ms.slave_dev_id is null

我们再看看执行计划

b6b99ffe3b8550123fb06ef6d3b78a46.png

这个就比较完美了,至此问题顺利解决!

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值