3

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

  • foos 在 start_date 被索引
  • moos 有 foos.id 作为外键

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

我需要做一些相当简单的事情:从 foos 中删除 start_date < 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 < X 的 moos 数量不大(<> 200/300k 记录)

  • 只有几千个moos引用了一个foo

  • 我在 mySQL 5.5 上,所以我无法解释“删除”,但是当我用“选择 1”替换时,解释表明 mySQL 正在做我认为它会做的事情:

    • 首先使用 start_date 索引找到正确的 foo
    • 然后看看 moos,所以它不应该是这么“长”的交易......</li>

有没有更好的方法来做到这一点,或者我错过了什么?

谢谢,

PJ

4

4 回答 4

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。加上当然添加任何索引。

于 2013-05-31T11:47:53.610 回答
0

另一个想法:

如果对 foo 的每个删除进行级联删除,外键可能是问题,它还必须检查 moo 以查看现在是否有任何孤立记录。是的,它不应该需要,因为您只是删除不匹配的,但查询计划器可能没有那么聪明。

于 2013-06-03T12:27:26.423 回答
0

我最终在 foo_id 上的 Moos 表中添加了一个索引,它解决了这个问题。我不知道为什么有必要说实话(考虑到 Moos 不是一张大桌子)......

感谢大家花时间提供帮助。

PJ

于 2013-06-05T09:56:43.460 回答
0

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

我看不出 Query #2 不工作的任何理由。会select foo_id from moos where foo_id is not null运行多久?distinct顺便说一句,我会在那里添加。

查询 #2 也可以重写为

delete foos FROM foos
WHERE start_date < "2013-05-30" 
  AND exists (select foo_id from moos where foo_id = foos.id);
于 2013-06-03T13:15:45.230 回答