优化" NOT IN(...)"查询数百万行

时间:2016-11-16 10:15:10

标签: mysql query-optimization

注意:我无法访问此问题所涉及的源代码/数据库。有问题的两个表位于不同的服务器上。

我与第三方公司合作,这些公司的系统与我们自己的系统集成在一起。他们有一个运行类似的查询;

DELETE FROM table WHERE column NOT IN(1,2,3,4,5,.....3 000 000)

它几乎引用NOT IN中的约300万个值。

我试图指出这似乎是一种删除多行并保留查询中记录的所有行的低效方法。问题是,由于我无法访问源代码/数据库,因此我不能完全确定建议作为解决方案。

我知道这个查询的想法是让目标服务器与源服务器同步。因此,如果在源服务器上删除了一行,则目标服务器将在运行此(和其他)查询时反映该更改。

凭借这种有限的知识,我可以向他们提出哪些可能的建议?

首先想到的是拥有某种标志列,表明它是否被删除。当同步脚本运行时,它将首先在目标服务器上对标记为已删除(或插入新行)的所有行执行更新,然后再执行第二次查询以删除标记为删除的所有行。

是否有更合理的方式来做这样的事情,牢记功能的彻底检修是不可能的。由于多种原因,只能对当前流程进行小的调整。

3 个答案:

答案 0 :(得分:1)

而不是

DELETE FROM your_table 
WHERE column NOT IN(1,2,3,4,5,.....3 000 000)

你可以做到

delete t1
from your_table t1
left join table_where_the_ids_come_from t2 on t1.column = t2.id
where t2.id is null

答案 1 :(得分:1)

  

我知道这个查询的想法是让目标服务器与源服务器同步。因此,如果在源服务器上删除了一行,则目标服务器将在运行此(和其他)查询时反映该更改。

我知道这很明显,但为什么这两台服务器不能使用复制保持同步?我猜这是因为除了这一张表,他们没有相同的数据。

如果开箱即用的复制不够灵活,您可以使用change-data capture tool

这个想法是该工具监视MySQL二进制日志流中的更改,并对它们做出反应。反应是用户定义的,它可以包括将相同的更改应用于另一个MySQL实例,这将使它们保持同步。

这是一个博客,展示如何使用Maxwell,这是开源CDC工具之一,这是Zendesk发布的: https://www.percona.com/blog/2016/09/13/mysql-cdc-streaming-binary-logs-and-asynchronous-triggers/

这种方法的一些优点:

  • 无需重新同步整个表格。您只会在发生增量更改时应用这些更改。
  • 无需每天安排重新同步或其他任何事情。由于增量更改可能很小,因此您可以立即应用更改。

答案 2 :(得分:0)

删除大量行将花费大量时间。这可能需要全表扫描。当它找到要删除的行时,它会强调撤消/重做日志。它会阻塞复制(如果使用这样的话)。等

您希望删除多少行?

最好将列表分成1000块。(这适用于使用IN(list of constants)JOIN。)但是,因为你正在做 NOT ,所以越来越粘。可能最好的方法是复制你想要的东西:

CREATE TABLE new LIKE real;
INSERT INTO new
    SELECT * FROM real WHERE id IN (...);  -- without NOT
RENAME TABLE real TO old,
             new TO real;
DROP TABLE old;

我在Big Deletes中详细介绍了分块,分区和其他技术。