[英]Why DELETE with subquery is much slower than with simple list of IDs?
我想根据主键从中等大小 (700K) 表中删除大量行。 认为,最好的方法应该使用SELECT
-subquery 来DELETE
源列表。 并在这里找到了具体的答案。 问题是:它比使用两个单独的查询慢得多(首先选择 ID,然后从表中删除这些 ID)。 为什么呢?
我也做了简单的测试用例:
CREATE TABLE `xyz` (
`xyzID` int(10) unsigned NOT NULL AUTO_INCREMENT,
`col1` int(10) unsigned NOT NULL DEFAULT '0',
PRIMARY KEY (`xyzID`)
) ENGINE=InnoDB;
用百万条记录填充它,然后:
DELETE FROM xyz
WHERE xyzID IN
(
SELECT xyzID
FROM
(
SELECT xyzID
FROM xyz
LIMIT 3000,1000
) a
);
Query OK, 1000 rows affected (53.52 sec)
删除 2000 行会使时间加倍:
Query OK, 2000 rows affected (1 min 48.25 sec)
但是删除没有子查询(首先选择)几乎没有时间(随机生成的id列表,在这里):
DELETE FROM test.xyz WHERE xyzID IN ( 660422,232794,573802,....
Query OK, 996 rows affected (0.04 sec)
为什么用子查询删除这么慢?
如果您阅读有关子查询的文档,您会发现一些可能导致此问题的原因: https : //dev.mysql.com/doc/refman/5.7/en/subquery-restrictions.html
优化器将使用exists
将不相关的WHERE IN (Subquery)
语句重写为相关语句。
因此,您的查询实际上可能是这样执行的:
DELETE FROM xyz t1
WHERE EXISTS (
(
SELECT 1
FROM
(
SELECT xyzID t3
FROM xyz
LIMIT 3000,1000
) a
where t1.xyzID = a.xyzID
);
现在每次删除一行时都需要执行相关子查询。
所以:对于 1000 次删除,您将在临时表a
上运行 1000 个子查询。 只有内部查询将保持不相关。
与in(valuelist)
相比,您正在运行1001
查询而不是1
。
文档:
这意味着 IN 子查询可能比使用 IN(value_list) 运算符编写的查询慢得多,该运算符列出子查询将返回的相同值。
解决这个问题的第一步是选择要删除的id到一个临时表中。 但是,当您尝试实际执行删除操作时,您可能仍会遇到慢子查询问题。
解决方案是使用DELETE xyz FROM xyz INNER JOIN xyz_temp WHERE xyz.id = xyz_temp.id
语法,它实现了相同的事情并且运行速度与简单连接一样快。
子查询意味着您要求数据库引擎将第一个表中的所有“N”行与您当时正在创建的另一个表中的所有“M”行进行比较。 这意味着你有 N*M 比较操作,要做到这一点,你需要加入表。 您正在构建的表有 N * M 行。
如果没有子查询,您只是将表中的所有“N”行与“X”关键字进行比较,其中“X”<<“M”。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.