mySQL删除查询优化

时间:2013-05-31 10:51:26

标签: mysql

我有两张桌子:食物和moos。

  • foos在start_date上编入索引
  • moos将foos.id作为外键

foos非常大(数百万条记录)。 moos不是(100k记录)。

我需要做一些相当简单的事情:使用start_date<删除来自foos的记录X并没有在moos中引用。我希望这不是一个特定的问题,但我无法让它工作(它永远挂起)我尝试了我认为将是“通常”的方式:

delete foos FROM foos LEFT JOIN moos ON foos.id = moos.foo_id WHERE moos.foo_id is null AND foos.start_date < "2013-05-30";

delete foos FROM foos WHERE start_date < "2013-05-30" AND id NOT IN (select foo_id from moos where foo_id is not null);

我应该补充:

  • 我总是选择X,以便通过start_date&lt;知道moos的数量。 X不大(&lt;> 200 / 300k记录)

  • 只有几千个moos引用了foo

  • 我在mySQL 5.5上,所以我无法解释“删除”,但当我用“select 1”替换时,解释建议mySQL正在做我想的那样:

    • 首先使用start_date索引查找正确的foos
    • 然后看看moos 所以它不应该是一个“长期”的交易......

有更好的方法可以做到这一点,还是我错过了什么?

谢谢,

PJ

4 个答案:

答案 0 :(得分:0)

怎么样......

CREATE TABLE foos_new
SELECT *
FROM
    foos
LEFT JOIN moos on foos.id = moos.foo_id
WHERE
    moos.foo_id IS NOT NULL
    OR
    (
        moos.foo_id IS NULL AND
        foos.start_date >= "2013-05-30"
    );

然后DROP原始表并将新表重命名为foos。另外,当然还要添加任何索引。

答案 1 :(得分:0)

另一个想法:

如果对foo中的每次删除执行级联删除,外键可能是问题,它还必须检查moo以查看是否存在任何孤立记录。是的,它不需要,因为你只是删除不匹配的,但查询计划可能不那么聪明。

答案 2 :(得分:0)

查询#1不起作用,因为foos.id = moos.foo_id仅在moos.foo_id不为NULL时才有效。与false中包含NULL的任何内容相比,NULL为NULL。添加and moos.foo_id is null将导致没有符合条件的记录。

我认为查询#2无法正常工作。 select foo_id from moos where foo_id is not null会运行多长时间?我会在那里添加distinct BTW。

查询#2也可以像

一样重写
delete foos FROM foos
WHERE start_date < "2013-05-30" 
  AND exists (select foo_id from moos where foo_id = foos.id);

答案 3 :(得分:0)

我最终在foo_id上添加了一个Moos表的索引,它解决了这个问题。 我不确定为什么必须诚实(考虑到Moos不是一张大桌子)......

感谢所有人花时间提供帮助。

PJ