[英]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_categories有97K条记录,而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 中讨论了这两种技术以及其他技术
至于查询公式:
NOT IN (SELECT ...)
和NOT EXISTS
往往是表现最差的。IN (SELECT ...)
和/或EXISTS
可能更好。DELETE
是另一种选择。它的工作原理类似于JOIN
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.