共计 3317 个字符,预计需要花费 9 分钟才能阅读完成。
这篇文章给大家分享的是有关 mysql 如何关联更新删除不走索引优化的内容。丸趣 TV 小编觉得挺实用的,因此分享给大家做个参考,一起跟随丸趣 TV 小编过来看看吧。
关于 update in 不走索引的:
首先 select 子查询形式是走索引的如下所示:
select * from acct_trans_payment where autopayflag= N and objectno in(
select serialno from acct_loan where businessstatus= 1 and accountingorgid= 10080201 )
执行计划如下:
然后 select 连接的形式:
select * from acct_trans_payment a,acct_loan b where a.objectno=b.serialno and a.autopayflag= N and b.businessstatus= 1 and b.accountingorgid= 10080201;
执行计划如下:
至此可以看出来,select 的 in 子查询的形式优化器发生了内部转换,转换成了 join 链接的形式,提高的性能!
然而 update 的却没有自动转换成 join 链接的形式,如下所示:
update acct_trans_payment set autopayflag= Y where autopayflag= N and objectno in(
select serialno from acct_loan where businessstatus= 1 and accountingorgid= 10080201 )
下文中有解释执行计划中的 select_type 中的 dependent subquery 的检索过程。
所以手动改写成 join 形式:
update acct_trans_payment a,acct_loan b set a.autopayflag= Y where a.objectno=b.serialno and a.autopayflag= N and b.businessstatus= 1 and b.accountingorgid= 10080201
效率提高了。。。。
关于 delete 的优化过程:
delete from cfs.acct_trans_payment where serialno in(
select serialno from jd.jd_flow where repaymentstype= 05
);
首先我们来解释一下图中的 dependent subquery 是什么意思:手册上的解释是,子查询中的 jd.jd_flow 表的 select,取决于外面的查询。就这么一句话,其实它表达的意思是:子查询中的查询方式依赖于外部(cfs.acct_payment_log)的查询。换句话说就是 jd.jd_flow 表的检索方式依赖于 cfs.acct_payment_log 表的数据,如这里 cfs.acct_payment_log 表得到的记录 serialno(where serialno in)刚好可以被 jd.jd_flow 表作为 unique_subquery 方式来获得它的相应的记录;换种写法如果此时 cfs.acct_payment_log 表扫描第一条记录得到的 serialno 为 10001 的话,那么后面子查询的语句就类似于这样的语句:
select serialno from jd.jd_flow where repaymentstype= 05 and serialno= 10001。此时这个语句就会被优化拿来优化,变成了上面的子查询的执行计划,由于 jd.jd_flow 的主键是 serialno,所以会走主键索引。
通过这个解释我们可以知道:全表扫描 cfs.acct_payment_log 表,将 cfs.acct_payment_log 的每条记录传递给 jd.jd_flow 表,jd.jd_flow 表通过主键索引方式来获得记录判断自身的条件,则找到一个满足此查询的语句。
总结:当看到 select_type 为 dependent subquery 的时候,就说明外表走的全表,然后把 where value in 中的外表中的每个 value 值给子查询表,然后遍历结果!
当子查询结果比较小的时候可以先把子查询查出来,然后写成如下形式:
select * from cfs.acct_trans_payment where serialno in(
101071256426871193705 ,
101184648601257984005 ,
101366238550600089605 ,
101506423110987776005 ,
101699991116782796905 ,
101872867624796569705 ,
99235027109713920005 )
对应的执行计划:
那么当子查询结果集比较大的时候,改怎么优化呢?
一样借助连接的形式
delete
from cfs.acct_trans_payment a join jd.jd_flow b where a.serialno =b.serialno and b.repaymentstype= 05
等价于
delete from cfs.acct_trans_payment where serialno in(
select serialno from jd.jd_flow where repaymentstype= 05
);
如下是两个的执行计划,显然性能提升了不少!
又如:
delete
a,b
from cfs.acct_trans_payment a join jd.jd_flow b where a.serialno =b.serialno and b.repaymentstype= 05
等价于
delete from cfs.acct_trans_payment where serialno in(
select serialno from jd.jd_flow where repaymentstype= 05
);
同时
delete from jd.jd_flow where repaymentstype= 05 and serialno in (select serialno from
cfs.acct_trans_payment)
也就是说会把两个表的符合条件的都删除。。。。。
题外话:关于 delete 的 join 形式:
delete from left join
DELETE A FROM YSHA A LEFT JOIN YSHB B ON A.code=b.code WHERE b.code is NULL;
等同于
DELETE FROM YSHA WHERE NOT EXISTS(SELECT 1 FROM YSHB B WHERE YSHA.code=b.code);
注意 delete 的时候不允许起别名,如下会报错!!!!
delete from cfs.acct_trans_payment a where EXISTS (select serialno from jd.jd_flow b where b.repaymentstype= 05 and a.serialno=b.serialno);
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near a where EXISTS (select serialno from jd.jd_flow b where b.repaymentstype= 05 at line 1
可以需要这样:
delete from cfs.acct_trans_payment where EXISTS (select serialno from jd.jd_flow b where b.repaymentstype= 05 and cfs.acct_trans_payment.serialno=b.serialno)
感谢各位的阅读!关于“mysql 如何关联更新删除不走索引优化”这篇文章就分享到这里了,希望以上内容可以对大家有一定的帮助,让大家可以学到更多知识,如果觉得文章不错,可以把它分享出去让更多的人看到吧!