我有一个大的(>Mil 行)MySQL 数据库因重复而混乱。我认为整个数据库的 1/4 到 1/2 可能都充满了它们。我需要快速摆脱它们(我的意思是查询执行时间)。它看起来是这样的:
ID(索引)| text1 | text2 | text3
text1&text2组合应该是唯一的,如果有任何重复项,则只能保留一种与text3的组合。例子:

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 可以是任何东西,它们不依赖于旧的表 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;

或者 SELECT DISTINCT 和其他变体。
虽然他们在小型数据库上工作,但我的查询执行时间非常长(实际上永远不会结束;> 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;

应该比任何通过或不同或子查询,或甚至通过顺序需要组快得多。这甚至不需要一个文件排序,这是要在一个大的临时表杀性能。仍然需要在原始表进行完全扫描,但没有避免。

其他提示

找到这个简单的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
)

这个查询中的所有记录,组由ID的区别字段和订单(意味着我们选择第一个不为空文字3记录)。然后,我们选择的ID从结果(这些都是很好的IDS ......他们不会被删除),并删除所有的ID没有被这些。

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

您已经这样做了“修复”我会申请UNIQUE INDEX(文本,文本2),以该表后。为了防止重复的posibility在未来。

如果你想要去的“创建一个新表,并取代旧的”路线。你可以用很内部的SELECT语句来创建插入语句。

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);

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

select * from my_tbl order by text3 desc
  • 我认为 text3 desc 的顺序会将 NULL 放在最后,但请仔细检查。

所有这些列上的索引可能会有很大帮助,但现在创建它们可能会非常慢。

对于一些重复的大表,您可能希望避免全表复制到另一个地方。一种方法是创建一个临时表抱着你想保持(与重复每个键)行,然后从原始表中删除重复。

给出一个例子此处

我没有与MySQL太多经验。如果其具有解析函数尝试:

delete from my_tbl
 where id in (
     select id 
       from (select id, row_number()
                            over (partition by text1, text2 order by text3 desc) as rn
               from my_tbl
               /* optional: where text1 like 'a%'  */
             ) as t2
       where rn > 1
     )

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

在运行此之前,确认“文字说明”将在最后一次在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;

您可以通过使用这个简单的查询中删除所有重复的条目。 这将选择所有的重复记录和删除它们。

 DELETE i1 
FROM TABLE i1
LEFT JOIN TABLE i2
  ON i1.id = i2.id
 AND i1.colo = i2.customer_invoice_id
 AND i1.id < i2.id
WHERE i2.customer_invoice_id IS NOT NULL
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top