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;