Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/mysql/60.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
这是删除重复的MySQL行的好方法吗?_Mysql_Duplicates_Sql Delete - Fatal编程技术网

这是删除重复的MySQL行的好方法吗?

这是删除重复的MySQL行的好方法吗?,mysql,duplicates,sql-delete,Mysql,Duplicates,Sql Delete,我看到了创建一个具有唯一行的备用临时MySQL表的解决方案,但我不喜欢这个想法,因为我的表非常大,移动它们会很麻烦(如果移动过程中出现错误,会造成巨大的问题) 然而,我确实发现了以下几点。您对此有何看法(要检查的副本是“字段名称”) 有人说这应该行得通,但我不太确定。你怎么认为?另外,索引是否会改变这个命令的性能,比如说,在“field_name”上有一个索引 编辑:在运行查询之前,是否有任何方法可以测试查询?据我所知,MySQL不支持删除查询的“解释”。该查询应该可以工作。拥有索引将改变性能,

我看到了创建一个具有唯一行的备用临时MySQL表的解决方案,但我不喜欢这个想法,因为我的表非常大,移动它们会很麻烦(如果移动过程中出现错误,会造成巨大的问题)

然而,我确实发现了以下几点。您对此有何看法(要检查的副本是“字段名称”)

有人说这应该行得通,但我不太确定。你怎么认为?另外,索引是否会改变这个命令的性能,比如说,在“field_name”上有一个索引


编辑:在运行查询之前,是否有任何方法可以测试查询?据我所知,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)