为什么使用子查询进行DELETE比使用简单的ID列表慢得多?

时间:2015-11-20 09:30:09

标签: mysql

我想根据主键从中等大小(700K)表中删除大量行。思想,最好的方法应该使用SELECT - DELETE源列表的子查询。并找到specific answer here too。问题是:它比使用两个单独的查询慢得多(首先选择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-list):

DELETE FROM test.xyz WHERE xyzID IN ( 660422,232794,573802,....
Query OK, 996 rows affected (0.04 sec)

为什么用子查询删除这么慢?

3 个答案:

答案 0 :(得分:2)

如果您阅读有关子查询的文档,您会发现一些可能导致此问题的原因: https://dev.mysql.com/doc/refman/5.7/en/subquery-restrictions.html





优化器将使用 exists 将不相关的 WHERE IN(子查询)语句重写为相关语句。





所以,你的查询实际上可能是这样执行的:




  DELETE FROM xyz t1
 WHERE EXISTS(
(
 SELECT 1&#xA) ; FROM
(
 SELECT xyzID t3
 FROM xyz
 LIMIT 3000,1000
)a
其中t1.xyzID = a.xyzID
);
  




现在需要执行相关子查询每次删除单行。


& #xA;

因此:对于1000个删除,您将在临时表 a 上运行1000个子查询。
 O内部查询将保持不相关。





与(valuelist)中的相比,您正在运行 1001 查询而不是<代码> 1

&#XA;&#XA;

实况:

&#XA;&#XA;
&#XA;

这意味着IN子查询可能比使用IN(value_list)运算符编写的查询慢得多,该运算符列出子查询将返回的相同值。

&#xA;
&# XA;

答案 1 :(得分:0)

子查询意味着您要求您的数据库引擎比较所有&#34; N&#34;第一个表中的行包含所有&#34; M&#34;您正在创建的另一个表中的行。这意味着您有N * M比较操作并且要执行此操作,您需要加入表格。您正在构建的表具有N * M行。

没有子查询,你只是比较所有&#34; N&#34;用&#34; X&#34;表示你的表格中的一行关键词在哪里 &#34; X&#34; &LT;&LT; &#34; M&#34;

答案 2 :(得分:0)

解决此问题的第一步是选择要删除的ID到临时表中。但是,当您尝试实际执行删除操作时,仍然可能会遇到慢子查询的问题。

解决方案是使用DELETE xyz FROM xyz INNER JOIN xyz_temp WHERE xyz.id = xyz_temp.id语法,该语法可以实现相同的功能,并且运行速度与简单的联接一样快。