针对DELETE查询的MySQL性能调整

问题描述 投票:2回答:4

[有人可以帮助我重写查询以加快执行时间吗?花费了[[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_categories

具有97K条记录,而MASTER中具有40K条记录。我们已经在MASTER.expirydate字段上创建了一个索引。
mysql sql performance query-optimization sql-delete
4个回答
1
投票
查询看起来很好。

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

master(expiry_date, userid) storefront_categories(userid)

第一个索引是master上子查询的

covering索引:这意味着数据库应该仅通过查看索引即可执行子查询(而索引中只有expiry_date,它仍然需要查看表数据以获取相关的userid)。

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

1
投票
我会尝试使用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)上。

1
投票
我建议您将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个字符。


0
投票
删除40K行时,需要花费一些时间。主要成本(假设有足够的索引编制和一个不错的查询)是“原子”删除的事务语义开销。这涉及为要删除的每一行制作一个副本,以防万一发生崩溃。这样,InnoDB可以使数据库恢复到崩溃前的状态。

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

[删除大量行时(无论百分比如何),最好分块执行。最好根据PRIMARY KEY浏览表格。

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

关于查询表述:

    取决于版本;旧版本的MySQL在某些方面做得不好。
  • [NOT IN (SELECT ...)NOT EXISTS往往表现最差。
  • [IN (SELECT ...)和/或EXISTS可能更好。
  • “多表DELETE是另一个选项。它的作用类似于JOIN
  • (底线:您没有说您正在运行哪个版本;我无法预测哪种形式是最好的。)
  • 我的博客避免了公式辩论。
© www.soinside.com 2019 - 2024. All rights reserved.