【问题标题】:How can I optimize this query to delete records that have no corresponding Id in another table? [closed]如何优化此查询以删除另一个表中没有对应 ID 的记录? [关闭]
【发布时间】:2020-10-15 22:51:20
【问题描述】:

我有一个包含 50 万条记录的“主”表,其中包含一个主键 ID (MovieId),其他几个表用作外键(多对多表)。

其中一些多对多表有数百万条记录(最多 2000 万条)。

我想从主表中不存在外键的多对多表中删除所有记录。这将极大地减小它们的大小(每条“仅”减少一百万或两百万条记录)。

但是实现这一点的 SQL 似乎非常耗时 - 基本上循环超过 2000 万条记录,每次都在主表中查看多达 50 万条记录,以查看 2000 万条中的外键是否50万条主表记录中存在多对多表记录作为主键。

我可以想象这需要很长时间。有没有(相对)快速的方法来做到这一点?

我的第一个想法是这样的:

DELETE FROM ACTORS_MOVIES_M2M
WHERE MovieiD NOT EXISTS (SELECT MovieiD FROM MOVIES_MAIN)

...再说一次,我认为这需要...一段时间。

【问题讨论】:

  • 该代码无法解析。

标签: sql sql-server foreign-keys query-optimization sql-delete


【解决方案1】:

你想写的查询:

delete m2m 
from actors_movies_m2m m2m
where not exists (select 1 from movies_main m where m.movieid = m2m.movieid)

movies_main(movieid) 上的索引有助于子查询快速执行(前提是movieidmovies_main 的主键,它已经存在)。

虽然这在技术上是正确的,但这可能不是最有效的方法。如果您要删除表的重要部分,那么清空并重新填充它可能更有效。

create table tmp_actors_movies_m2m as
select * 
from actors_movies_m2m m2m
where exists (select 1 from movies_main m where m.movieid = m2m.movieid)

truncate table actors_movies_m2m;  -- back it up first!

insert into actors_movies_m2m 
select * 
from tmp_actors_movies_m2m;

drop table actors_movies_m2m;

请注意,您的问题本身表明存在潜在的设计问题。您可以通过使用 on delete cascade 选项设置适当的外键从一开始就避免孤立记录:

create table actors_movies_m2m  (
    ... -- columns here
    movieid int references movies_main (movieid) on delete cascade
);

【讨论】:

  • 在事实之后(在填充表之后)添加索引会产生任何影响,还是仅在添加记录时才起作用。 IOW,添加索引时是否会对已存在的记录进行索引?
猜你喜欢
  • 2012-01-02
  • 2010-09-21
  • 2015-11-28
  • 1970-01-01
  • 2012-08-16
  • 1970-01-01
  • 2013-10-07
  • 1970-01-01
  • 2013-04-04
相关资源
最近更新 更多