繁体   English   中英

用于 DELETE 查询的 MySQL 性能调优

[英]MySQL performance tuning for DELETE query

任何人都可以帮助我重新编写查询以加快执行时间吗? 执行耗时37秒。

DELETE FROM storefront_categories 
WHERE userid IN (SELECT userid 
                FROM MASTER 
                where expirydate<'2020-2-4' 
                )

同时,这个查询只执行了 4.69 秒。

DELETE FROM storefront_categories 
WHERE userid NOT IN (SELECT userid FROM MASTER)

storefront_categories97K条记录,而MASTER 表40K条记录。 我们在 MASTER.expirydate 字段上创建了一个索引。

查询看起来很好。

我建议使用以下索引进行优化:

master(expiry_date, userid)
storefront_categories(userid)

第一个索引是master上子查询的覆盖索引:这意味着数据库应该能够通过查看索引来执行子查询(而索引中只有expiry_date ,它仍然需要查看表数据以获取相关的userid )。

第二索引让数据库优化in操作。

我会尝试使用exists

DELETE 
FROM storefront_categories 
WHERE EXISTS (SELECT 1 
              FROM MASTER M 
              WHERE M.userid = storefront_categories.userid AND
                    M.expirydate <'2020-02-04'  
              );

索引会在这里我希望在storefront_categories(userid) & MASTER(userid, expirydate)

我建议您使用NOT EXISTS和正确的索引:

DELETE sc
    FROM storefront_categories sc
    WHERE NOT EXISTS (SELECT 1
                      FROM master m
                      WHERE m.userid = sc.userid AND
                            m.expirydate < '2020-02-04' 
                     );

您想要的索引位于master(userid, expirydate) 列的顺序很重要。 对于此版本, storefront_categories上的索引无济于事。

请注意,我更改了日期格式。 我建议使用 YYYY-MM-DD 以避免歧义——并使用完整的 10 个字符。

删除 40K 行时,预计需要时间。 主要成本(假设有足够的索引和适当的查询)是“原子”删除的事务语义的开销。 这涉及制作被删除的每一行的副本,以防万一发生崩溃。 这样,InnoDB 可以将数据库恢复到崩溃前的状态。

删除表的 40% 时,将行复制到另一个表然后交换表要快得多。

删除大量行(不考虑百分比)时,最好分块进行。 最好根据PRIMARY KEY遍历表。

我在http://mysql.rjweb.org/doc.php/deletebig 中讨论了这两种技术以及其他技术

至于查询公式:

  • 它是版本相关的; 旧版本的 MySQL 在某些方面做得很差。
  • NOT IN (SELECT ...)NOT EXISTS往往是表现最差的。
  • IN (SELECT ...)和/或EXISTS可能更好。
  • “多表DELETE是另一种选择。它的工作原理类似于JOIN
  • (底线:您没有说明您运行的是哪个版本;我无法预测哪种配方最好。)
  • 我的博客避免了配方辩论。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM