MySQL大表场景下多关联表批量删除的高效实现方案咨询
解决方案
首先明确你原有两个方案的核心问题:
- 内连接删除:要求三张表同时存在匹配行才会触发删除,无对应product的category会被漏删,不符合需求
- 左连接删除慢:你将aid过滤条件写在了左连接的ON子句中,会先做全表关联再过滤,生成超大临时表,性能极差
方案1:事务级一致性删除(适合需要强一致的场景)
按照子表到父表的顺序执行删除,每一步都走索引,无临时表开销,不会漏删:
START TRANSACTION; -- 删除匹配的products数据 DELETE p FROM products p INNER JOIN categories c ON p.cid = c.cid INNER JOIN accounts a ON c.aid = a.aid WHERE a.aid > 63 AND a.aid < 123; -- 删除匹配的categories数据(无论是否有对应products都会删除) DELETE c FROM categories c INNER JOIN accounts a ON c.aid = a.aid WHERE a.aid > 63 AND a.aid < 123; -- 若需要同时删除对应accounts行,可取消注释下行 -- DELETE a FROM accounts a WHERE a.aid > 63 AND a.aid < 123; COMMIT;
优势
- 所有删除逻辑都用内连接,走aid、cid的索引,执行效率高
- 不会漏删无product的category,完全符合需求
- 事务包裹保证删除一致性,要么全部生效要么全部回滚
方案2:超大数据量分批删除(适合符合条件的数据量超过10万级的场景)
避免长事务锁表、主从延迟问题,每次删除固定行数循环执行即可:
-- 第一步:循环删除products,每次删1000行,直到返回影响行数为0 DELETE p FROM products p INNER JOIN categories c ON p.cid = c.cid INNER JOIN accounts a ON c.aid = a.aid WHERE a.aid > 63 AND a.aid < 123 LIMIT 1000; -- 第二步:循环删除categories,每次删1000行,直到返回影响行数为0 DELETE c FROM categories c INNER JOIN accounts a ON c.aid = a.aid WHERE a.aid > 63 AND a.aid < 123 LIMIT 1000;
优势
- 每次锁表时间极短,不会阻塞其他业务对表的正常读写
- 不会生成超大事务,避免主从同步延迟
可选优化
如果删除的数据量占表总数据量的30%以上,删除完成后可执行OPTIMIZE TABLE products, categories;整理表碎片,释放磁盘空间,提升后续查询性能。
内容的提问来源于stack exchange,提问作者Jim
相关产品推荐
相关产品推荐

