【问题标题】:MySQL compare and delete to large tables ~30m recordsMySQL比较和删除大表~30m记录
【发布时间】:2018-12-18 12:43:42
【问题描述】:

我需要找到 table1 中存在但 table2 中不存在的值,然后从 table1 中删除这些值(两个表都有主键)。问题是表太大,像下面这样的查询需要很多时间:

DELETE
FROM table_1 t1
WHERE NOT EXISTS ( SELECT primarykey FROM table_2 t2 WHERE t1.id = t2.primarykey )

有没有办法分块执行任务,例如一次 300k 行?还是更好的优化解决方案?

【问题讨论】:

  • where t1.id < 300000 * n
  • 您可能会在子查询上使用limit,这样您只能返回 X 条记录...连接而不是子查询可能会更快。我在子查询时遇到子查询不使用索引的问题。
  • @user3783243 你能举一个使用连接和限制的查询示例吗?
  • FROM table_1 t1 join primarykey as p1 t1.id = p1.primarykey 然后删除WHERE 我认为您不需要limit 但试一试,看看它是如何执行的。您也可以使用explain 查看正在使用/未使用的索引。
  • @ITFreak - 实际删除的行的百分比是多少?要删除的行是否位于表的“末尾”?

标签: php mysql sql performance


【解决方案1】:

我会使用左连接而不是子查询;那会快很多。然后,您可以删除连接表中不能具有NULL 值的字段的连接中具有NULL 值的行。

看起来像这样:

DELETE table_1 
FROM table_1 t1
LEFT JOIN table_2 t2
    ON t1.id = t2.primarykey
WHERE t2.id IS NULL

【讨论】:

  • 可以对有 3000 万条记录的表运行此查询吗?
  • @ITFreak 我不明白为什么,但我想这取决于将被删除的行数。你试过并计时了吗?
  • @jeroen - 为 30M 删除构建所有 ROLLBACK 内容将需要很长时间。
  • @RickJames 当然,但我认为只有 30M 记录中的一小部分需要删除。但是,如果没有来自 OP 的更多信息,就无法判断。
【解决方案2】:

一次只删除 1K 行。请记住,InnoDB 需要挂起所有已删除的行以防崩溃。 (然后它可以ROLLBACK 乱七八糟。)如果您确实删除了块,请不要使用OFFSET。相反,请使用PRIMARY KEY。 (下面的链接中有更多详细信息。)

如果你要删除一个表的大部分行,那么删除会快很多

CREATE TABLE new ...;   -- either say "LIKE real" or spell out schema
INSERT INTO new
    SELECT ... FROM real WHERE opposite-test;
RENAME TABLE real TO old,
             new TO real;   -- atomic and fast
DROP TABLE old;   -- after you verify that it worked.

关于大删除的更多提示:http://mysql.rjweb.org/doc.php/deletebig
This 还讨论了批量处理表的一部分的案例。

【讨论】:

  • 这就是我需要的......使用循环的解决方案(在你提到的链接中)对我有用。谢谢。
猜你喜欢
  • 2011-03-11
  • 1970-01-01
  • 2020-12-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-05-19
  • 2021-10-04
相关资源
最近更新 更多