php - php从MySql表中删除重复行

我有一个脚本在我的MySql表中找到重复的行,该表包含40,000,000行。 但它是非常缓慢的,是否有一种更简单的方法来找到重复的记录,而无需使用php?

这是我目前使用的脚本


 $find = mysql_query("SELECT * FROM pst_nw ID <'1000'");


 while ($row = mysql_fetch_assoc($find))


 {


 $find_1 = mysql_query("SELECT * FROM pst_nw add1 = '$row[add1]' AND add2 = '$row[add2]' AND add3 = '$row[add3]' AND add4 = '$row[add4]'");


 if (mysql_num_rows($find_1)> 0) {


 mysql_query("DELETE FROM pst_nw WHERE ID ='$row[ID]'}



 }



时间:

你有很多选择。

让数据库完成工作

使用唯一索引创建表的副本- 然后从源表中将数据插入其中:


CREATE TABLE clean LIKE pst_nw;


ALTER IGNORE TABLE clean ADD UNIQUE INDEX (add1, add2, add3, add4);


INSERT IGNORE INTO clean SELECT * FROM pst_nw;


DROP TABLE pst_nw;


RENAME TABLE clean pst_nw;



这样做的好处是,在删除源表之前,你可以验证新表是否正确。 缺点是它占用了两倍的空间, 并且( 相对) 执行速度慢。

让数据库做 #2 工作

你还可以通过以下方式实现所需的结果:


set session old_alter_table=1;


ALTER IGNORE TABLE pst_nw ADD UNIQUE INDEX (add1, add2, add3, add4);



第一个命令是的一个变通方法,忽略标志。

这个的优点是没有临时表的混乱- 缺点是运行之前, 你不能检查你的更新是否完全符合你的预期 。

例如:


 CREATE TABLE `foo` (


 `id` int(10) NOT NULL AUTO_INCREMENT,


 `one` int(10) DEFAULT NULL,


 `two` int(10) DEFAULT NULL,


 PRIMARY KEY (`id`)


)



insert into foo values (null, 1, 1);


insert into foo values (null, 1, 1);


insert into foo values (null, 1, 1);



select * from foo;


+----+------+------+


| id | one | two |


+----+------+------+


| 1 | 1 | 1 |


| 2 | 1 | 1 |


| 3 | 1 | 1 |


+----+------+------+


3 row in set (0.00 sec)



set session old_alter_table=1;


ALTER IGNORE TABLE foo ADD UNIQUE INDEX (one, two);



select * from foo;


+----+------+------+


| id | one | two |


+----+------+------+


| 1 | 1 | 1 |


+----+------+------+


1 row in set (0.00 sec)



不要在数据库外做这种事情

特别是在数据库外部有4000万行做这样的事情可能需要花费大量时间,而且可能根本无法完成。 任何留在数据库中的解决方案都将更快,更可靠。

通常在这样的问题中,问题是"我有重复行,只保留一行,任何一行"。

但是从代码来看你想要的是: "add1,add2,add3,add4的一组复制,删除所有带有 <1000的副本"。 在这种情况下,使用INSERT IGNORE从表复制到另一个表不会做你想要的 - 甚至可能保留ID较低的行并丢弃后续的行。

我相信你需要运行这样的东西来收集所有"坏ID "(带有重复的ID,高于1000的副本;在这段代码中我使用了"AND bad.ID 如果这不是您想要的,您可以在AND bad.ID <1000 and good.ID> 1000中修改它


CREATE TABLE bad_ids AS


 SELECT bad.ID FROM pst_nw AS bad JOIN pst_nw AS good


 ON ( bad.ID <1000 AND bad.ID <good.ID


 AND bad.add1 = good.add1


 AND bad.add2 = good.add2


 AND bad.add3 = good.add3


 AND bad.add4 = good.add4 );



一旦你把所有坏ID都写进一张表,


DELETE pst_nw.* FROM pst_nw JOIN bad_ids ON (pst_nw.ID = bad_ids.ID);



性能将从这个顺序的add1,add2,add3,add4和ID上的(非唯一的,可能只是临时的)索引中受益匪浅。

...