Mysql 除给定列表中的行号外,每隔一行删除一次

Mysql 除给定列表中的行号外,每隔一行删除一次,mysql,database,delete-row,large-data-volumes,Mysql,Database,Delete Row,Large Data Volumes,所以基本上我想做的是:我有一个account表,我有一个acct_id列表:3,24,515,6326,17,假设我在表中有大约100000个帐户,除了我给定列表中有account_id的那一行之外,删除所有其他行的最有效方法是什么 我想出了这样的想法: delete from account where acct_id is not in (3, 24, 515, 6326, 17); 我听说这个查询很慢,因为它是递归的。考虑一下我所拥有的行数,这将是非常缓慢的。有什么更好的方法可以做到这一

所以基本上我想做的是:我有一个account表,我有一个acct_id列表:3,24,515,6326,17,假设我在表中有大约100000个帐户,除了我给定列表中有account_id的那一行之外,删除所有其他行的最有效方法是什么

我想出了这样的想法:

delete from account where acct_id is not in (3, 24, 515, 6326, 17);
我听说这个查询很慢,因为它是递归的。考虑一下我所拥有的行数,这将是非常缓慢的。有什么更好的方法可以做到这一点

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 */ 根据数据库的风格、索引、是否分布等,这可能需要大量的工作。即使在完全日志化的数据库中也能有效工作的替代方案是:

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 */
您的查询对我来说似乎很好,但看看您是否正在尝试优化查询。

您的查询对我来说似乎很好,但看看您是否正在尝试优化查询。

如果您有帐户id索引,我看不出您的查询速度慢的任何原因。 据我所知

in (3, 24, 515, 6326, 17)
只是语法上的糖

acct_id != 3 AND acct_id != 24 ...

这应该足够快。

如果你有账户id的索引,我看不出你的查询速度慢的原因。 据我所知

in (3, 24, 515, 6326, 17)
只是语法上的糖

acct_id != 3 AND acct_id != 24 ...

这应该足够快。

不是特定于MySQL的,但是一般来说,删除是相对昂贵的,因为它们需要引擎进行一系列选择,以确保删除正确的记录以及实际的删除。当然,根据引擎和设置,您也会在事务日志中添加大量事务

如果你只想保留一小部分记录,而想扔掉一大部分记录,那么你可以通过作弊获得更快的表现


您复制要保留的记录,删除或截断表,然后将保留者添加回数据库。

并非特定于MySQL,但一般来说,删除相对昂贵,因为它们需要引擎执行一系列选择,以确保删除正确的记录以及实际的删除。当然,根据引擎和设置,您也会在事务日志中添加大量事务

如果你只想保留一小部分记录,而想扔掉一大部分记录,那么你可以通过作弊获得更快的表现


复制要保留的记录,删除或截断表,然后将保留项重新添加。

我的解决方案是避免删除并使用truncate table,因为删除数据库时会执行两个操作。删除记录并将其写入回滚段

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

-- 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;

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

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

-- 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;

这似乎与我提出的解决方案几乎相同……请再解释一下这在大量数据上是如何有效的?我在写答案时没有看到SQL语句。你后来加的吗?我之前没有把它放在代码标签里。但你建议的替代方案似乎很有希望。由于他在使用MySQL,最后一步可以将table2重命名为TABLE;当心删除表的副作用:需要重新创建索引和其他约束。我更喜欢使用截断表。在下面发布了一个解决方案。这似乎与我提出的解决方案几乎相同……请再解释一下这对大量数据是如何有效的?我在写答案时没有看到SQL语句。你后来加的吗?我之前没有把它放在代码标签里。但你建议的替代方案似乎很有希望。由于他在使用MySQL,最后一步可以将table2重命名为TABLE;当心删除表的副作用:需要重新创建索引和其他约束。我更喜欢使用截断表。在下面发布了一个解决方案。您是否有表关系-从其他表到该表的外键?你打算在那张表上有多少索引?这些可能会极大地改变答案:例如,删除一个表可能不是选项,或者简单的删除性能与复杂的方式相同。了解您正在优化的内容:它可能没有被破坏。@fei我知道这个问题很老,但是我可以知道为什么或者在哪里听说您的查询很慢吗?您是否有表关系-从其他表到这个表的外键?你打算在那张表上有多少索引?这些可能会极大地改变答案:例如,删除一个表可能不是选项,或者简单的删除性能与复杂的方式相同。知道你在干什么吗
胆小鬼:可能还没破。@fei我知道这个问题很老了,但我可以知道你为什么或者在哪里听到你的问题很慢吗?