删除除给定列表中的行号之外的所有其他行

时间:2009-11-16 23:21:13

标签: mysql database delete-row large-data-volumes

所以基本上这就是我想要做的事情:我有一个帐户表,我有一个acct_id列表:(3,24,515,6326,17),假设我在表中有大约100,000个帐户,最多的是什么删除除给定列表中的account_id之外的所有其他行的有效方法吗?

我想出了类似的东西:

delete from account where acct_id is not in (3, 24, 515, 6326, 17);

我听说这个查询很慢,因为它是递归的或者其他东西。考虑我拥有的行数,这将是非常慢。什么是更好的方法呢?

5 个答案:

答案 0 :(得分:4)

delete from table
 where not acct_id in (3, 24, 515, 6326, etc.);

根据数据库的风格,索引,分发与否等,这可能是很多工作。即使在完整日记数据库中也能有效工作的替代方案是:

create table2 temp as /* create new table from the rows to keep */
   select *
   from table
   where acct_id in (3, 24, 515, 6326, etc.);
drop table;           /* discard table */
create table as       /* copy new table to rename */
  select * from table2;
drop table2;          /* get rid of temporary table */

答案 1 :(得分:0)

您的查询似乎对我很好,但如果您尝试优化查询,请查看Explain

答案 2 :(得分:0)

如果你有一个关于acct_id的索引,我看不出你的查询应该很慢的任何理由。 据我所知

in (3, 24, 515, 6326, 17)

只是

的语法糖
acct_id != 3 AND acct_id != 24 ...

应该足够快。

答案 3 :(得分:0)

不是特定于MySQL,但删除通常是相对昂贵的,因为它们需要引擎做一堆选择以确保它删除正确的记录以及实际的删除。最后还会在事务日志中添加大量事务(当然,取决于引擎和设置)。

如果您只想保留一小组记录并想要丢弃一大套记录,那么您可以通过作弊来获得更快的表现......

您复制要保留的记录,然后删除或截断表格,然后再添加“守护者”。

答案 4 :(得分:0)

我的解决方案是避免DELETE并使用TRUNCATE表,因为当你删除数据库时会做两个操作。删除并将记录写入回滚段。

当然,这意味着在截断时没有回滚。

-- copy the few records into a temp table
select into temp 
 select * from account
 where acct_id in (3, 24, 515, 6326, 17);

-- truncate is super fast
truncate table account;

-- put back the few records
insert into account select * from temp;

drop table temp;