Я знаю, что это старая ветка, но у меня есть несколько грязный метод, который намного быстрее и настраивается, с точки зрения скорости, я бы сказал, 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;