MySQL快速删除大数据库中的重复项

我有大的(> Mil行)MySQL数据库被重复项弄乱。 我认为这可能是整个数据库的四分之一到二分之一。 我需要摆脱他们快(我的意思是查询执行时间)。 以下是它的外观:
id(index)| text1 | text2 | 文字3
text1和text2的组合应该是唯一的,如果有任何重复,只剩下一个text3的组合NOT NULL。 例:

1 | abc | def | NULL 2 | abc | def | ghi 3 | abc | def | jkl 4 | aaa | bbb | NULL 5 | aaa | bbb | NULL 

…变为:

 1 | abc | def | ghi #(doesn't realy matter id:2 or id:3 survives) 2 | aaa | bbb | NULL #(if there's no NOT NULL text3, NULL will do) 

新的寒冷是什么,他们不依赖于旧桌面ID。
我尝试过这样的事情:

 CREATE TABLE tmp SELECT text1, text2, text3 FROM my_tbl; GROUP BY text1, text2; DROP TABLE my_tbl; ALTER TABLE tmp RENAME TO my_tbl; 

或selectDISTINCT和其他变化。
虽然他们在小型数据库上工作,但在我的查询执行时间是巨大的(实际上从来没有结束,> 20分钟)

有没有更快的方法来做到这一点? 请帮我解决这个问题。

我相信这将做到这一点,使用重复键+ ifnull():

 create table tmp like yourtable; alter table tmp add unique (text1, text2); insert into tmp select * from yourtable on duplicate key update text3=ifnull(text3, values(text3)); rename table yourtable to deleteme, tmp to yourtable; drop table deleteme; 

应该比任何需要group by或distinct或subquery,甚至order by的东西快得多。 这甚至不需要一个文件夹,这将会在一个大的临时表上杀死性能。 仍然需要对原始表进行全面扫描,但是没有办法避免。

find这个简单的1行代码来完成我所需要的:

 ALTER IGNORE TABLE dupTest ADD UNIQUE INDEX(a,b); 

取自: http : //mediakey.dk/~cc/mysql-remove-duplicate-entries/

 DELETE FROM dups WHERE id NOT IN( SELECT id FROM ( SELECT DISTINCT id, text1, text2 FROM dups GROUP BY text1, text2 ORDER BY text3 DESC ) as tmp ) 

这将查询所有的logging,由区分字段的组和按IDsorting(意味着我们select第一个非空的text3logging)。 然后我们从结果中selectid(这些都是好的id …他们不会被删除)并删除所有不是那些的id。

像这样的任何查询影响整个表将是缓慢的。 你只需要运行它,让它滚出来,以便将来可以防止它。

完成这个“修复”之后,我会将UNIQUE INDEX(text1,text2)应用于该表。 为了防止未来重复的可能性。

如果你想去“创build一个新的桌子,取代旧的”路线。 你可以使用内部的select语句来创build你的insert语句。

特定于MySQL(假设新表名为my_tbl2并具有完全相同的结构):

 INSERT INTO my_tbl2 SELECT DISTINCT id, text1, text2, text3 FROM dups GROUP BY text1, text2 ORDER BY text3 DESC 

有关更多信息,请参阅MySQL INSERT … SELECT 。

删除重复项而不删除外键

 create table tmp like mytable; ALTER TABLE tmp ADD UNIQUE INDEX(text1, text2, text3, text4, text5, text6); insert IGNORE into tmp select * from mytable; delete from mytable where id not in ( select id from tmp); 

如果您可以创build一个新表,请使用text1 + text2字段上的唯一键。 然后插入到表中忽略错误(使用INSERT IGNORE语法):

 select * from my_tbl order by text3 desc 
  • 我认为通过text3 desc的顺序会把NULL最后,但仔细检查。

所有这些列的索引可以帮助很多,但现在创build它们可能会非常缓慢。

对于重复数量较less的大型表格,您可能希望避免将整个表格复制到另一个地方。 一种方法是创build一个临时表,其中包含要保留的行(对于每个具有重复项的项),然后从原始表中删除重复项。

这里给出一个例子。

我没有太多的MySQL经验。 如果它具有分析function,请尝试:

从my_tbl中删除
 在哪里id(
     selectID 
        from(select id,row_number()
                             (由text1划分,text2由text3 desc划分)作为rn
               从my_tbl
                / *可选:其中text1像“a%”* /
              )为t2
       其中> 1
      )

可选的where子句使得你必须多次运行它,每个字母等等。在text1上创build一个索引?

在运行这个之前,确认“text desc”会在MySQL中排除最后一个空值。

我知道这是一个旧的线程,但我有一个有点凌乱的方法,是更快,可定制的速度,我说10秒,而不是100秒(10:1)。

我的方法需要所有你想要避免的杂乱的东西:

  • 由(和有)
  • 用ORDER BY组连接
  • 2个临时表
  • 使用磁盘上的文件!
  • 不知何故(PHP?)后删除文件

但是当你谈论数百万(或者在我的情况下,数百万)这是值得的。

反正它不多,因为评论是葡萄牙语,但这是我的样本:

编辑 :如果我得到意见,我会进一步解释它是如何工作的:)

 START TRANSACTION; DROP temporary table if exists to_delete; CREATE temporary table to_delete as ( SELECT -- escolhe todos os IDs duplicados menos os que ficam na BD -- A ordem de escolha dos IDs é dada por "ORDER BY campo_ordenacao DESC" em que o primeiro é o que fica right( group_concat(id ORDER BY campos_ordenacao DESC SEPARATOR ','), length(group_concat(id ORDER BY campos_ordenacao DESC SEPARATOR ',')) - locate(",",group_concat(id ORDER BY campos_ordenacao DESC SEPARATOR ',')) ) as ids, count(*) as c -- Tabela a eliminar duplicados FROM teste_dup -- campos a usar para identificar duplicados group by test_campo1, test_campo2, teste_campoN having count(*) > 1 -- é duplicado ); -- aumenta o limite desta variável de sistema para o máx SET SESSION group_concat_max_len=4294967295; -- envia os ids todos a eliminar para um ficheiro select group_concat(ids SEPARATOR ',') from to_delete INTO OUTFILE 'sql.dat'; DROP temporary table if exists del3; create temporary table del3 as (select CAST(1 as signed) as ix LIMIT 0); -- insere os ids a eliminar numa tabela temporaria a partir do ficheiro load data infile 'sql.dat' INTO TABLE del3 LINES TERMINATED BY ','; alter table del3 add index(ix); -- elimina os ids seleccionados DELETE teste_dup -- tabela from teste_dup -- tabela join del3 on id=ix; COMMIT;