这是删除重复的MySQL行的好方法吗?
我看到了创建一个具有唯一行的备用临时MySQL表的解决方案,但我不喜欢这个想法,因为我的表非常大,移动它们会很麻烦(如果移动过程中出现错误,会造成巨大的问题) 然而,我确实发现了以下几点。您对此有何看法(要检查的副本是“字段名称”) 有人说这应该行得通,但我不太确定。你怎么认为?另外,索引是否会改变这个命令的性能,比如说,在“field_name”上有一个索引这是删除重复的MySQL行的好方法吗?,mysql,duplicates,sql-delete,Mysql,Duplicates,Sql Delete,我看到了创建一个具有唯一行的备用临时MySQL表的解决方案,但我不喜欢这个想法,因为我的表非常大,移动它们会很麻烦(如果移动过程中出现错误,会造成巨大的问题) 然而,我确实发现了以下几点。您对此有何看法(要检查的副本是“字段名称”) 有人说这应该行得通,但我不太确定。你怎么认为?另外,索引是否会改变这个命令的性能,比如说,在“field_name”上有一个索引 编辑:在运行查询之前,是否有任何方法可以测试查询?据我所知,MySQL不支持删除查询的“解释”。该查询应该可以工作。拥有索引将改变性能,
编辑:在运行查询之前,是否有任何方法可以测试查询?据我所知,MySQL不支持删除查询的“解释”。该查询应该可以工作。拥有索引将改变性能,但这实际上取决于表的大小 至于测试,我会将数据的一个子集复制到一个临时表中,并在实际表上运行temp表之前在temp表上运行该命令
请记住,在执行任何主要批处理作业之前,请始终备份表,以便您可以始终回滚。我使用的方法避免了
连接
的情况,并且应该更快:
DELETE FROM table1 WHERE id NOT IN (SELECT MIN(x.id) FROM table1 AS x GROUP BY x.field_name);
subselect收集要保留的id列表。这将允许您为每个字段\u name
保留一个唯一的行。DELETE
语句将删除所有额外的重复行
另外,是的,
字段的索引\u name
字段将提高查询的性能。请注意,您显示的查询将删除两个重复项。我想你想保留其中一个
下面是我将如何编写此查询:
DELETE t1 FROM table1 AS t1 JOIN table1 AS t2
ON t1.id > t2.id AND t1.field_name = t2.field_name;
通过使用大于而不是不等于,您只删除一行(后面的一行),而不是同时删除两行
在(id、字段名称)上添加复合索引可能会有所帮助。您应该通过MySQL的解释来确认这一点,以获得优化报告。但是EXPLAIN
只支持SELECT
查询,因此您应该运行等效的SELECT
来确认优化:
EXPLAIN SELECT * FROM table1 AS t1 JOIN table1 AS t2
ON t1.id > t2.id AND t1.field_name = t2.field_name;
您还询问了有关测试的问题。我建议将包含重复项的行的示例复制到测试中的表中
数据库:
CREATE TABLE test.table1test SELECT * FROM realdb.table1 LIMIT 10000;
现在,您可以对样本数据执行实验,直到您确信DELETE
解决方案是正确的
USE test;
SET autocommit = 0;
DELETE ...
ROLLBACK;
我建议在test
数据库中命名scratch表,使其与真实数据库中的真实表不同。以防万一,当您意外地仍然使用真实数据库作为默认数据库时,您运行了一个实验性的DELETE
您的评论如下:
USE test
是一个mysql客户端内置命令。它将test
数据库设置为默认数据库。当您在查询中命名表而不使用数据库名称限定它们时,这将是默认数据库。看
SET autocommit=0
关闭隐式提交每个查询事务的默认行为。因此,您必须显式地发出COMMIT
或ROLLBACK
命令来完成事务。看
在进行实验时,值得使用ROLLBACK
,因为它会放弃在该事务中所做的更改。这是一种快速返回测试数据初始状态的方法,因此您可以尝试另一个实验
DELETE t1
不是打字错误<代码>删除
删除行,而不是整个表t1
是满足语句条件的每一行的别名(尽管条件可能包括表中的每一行)。请参见第页的多表删除说明
有点像在PHP中运行一个循环,然后使用一个变量在循环中迭代:
for($i=0;$iI)将要发送另一个示例查询,但是,您测试过这个吗?在我看来,这两个记录都会被删除。您可以用“选择”替换“删除”测试您的查询。实际上,MySQL中使用的任何GROUP BY
都会调用一个临时表,这严重影响性能。@Bill-刚刚在我的一个测试数据库上做了一个快速测试。当然,只有30000行,但是GROUP BY
在我使用它的情况下明显优于JOIN
。嗯,这很好ope它也适用于OP的数据库。谢谢你的帮助法案!你已经获得了对你答案的投票,所以我假设你的答案是最好的解决方案(不要说其他的都不好)。请你解释一下以“USE test;SET…”开头的代码块是什么意思?另外,为了确保,大于号的使用将确保删除所有重复项,即使有超过1个重复项(例如,5个)?非常感谢。还忘了问:您的解决方案的第一块代码不是打字错误,对吗?您放了“删除t1”.这不意味着它会删除一整张桌子或其他东西吗?对不起,所有的问题,这对我来说只是有点复杂=)我只是想停下来,再次感谢你写了这么精彩的文章。两年多后我仍然提到它!
USE test;
SET autocommit = 0;
DELETE ...
ROLLBACK;
mysql> create table table1 (id serial primary key, field_name varchar(10));
Query OK, 0 rows affected (0.45 sec)
mysql> insert into table1 (field_name)
values (42), (42), (42), (42), (42), (42);
Query OK, 6 rows affected (0.00 sec)
Records: 6 Duplicates: 0 Warnings: 0
mysql> select * from table1;
+----+------------+
| id | field_name |
+----+------------+
| 1 | 42 |
| 2 | 42 |
| 3 | 42 |
| 4 | 42 |
| 5 | 42 |
| 6 | 42 |
+----+------------+
6 rows in set (0.00 sec)
mysql> delete t1 from table1 t1 join table1 t2
on t1.id > t2.id and t1.field_name = t2.field_name;
Query OK, 5 rows affected (0.00 sec)
mysql> select * from table1;
+----+------------+
| id | field_name |
+----+------------+
| 1 | 42 |
+----+------------+
1 row in set (0.00 sec)