Ich habe große (> Mil-Zeilen) MySQL-Datenbank durch Duplikate durcheinander gebracht. Ich denke, es könnte 1/4 bis 1/2 der gesamten Datenbank sein, die mit ihnen gefüllt ist. Ich muss sie schnell loswerden (ich meine Abfrageausführungszeit). So sieht es aus:
id (index) | text1 | text2 | Die
Kombination aus text3 text1 und text2 sollte eindeutig sein. Wenn Duplikate vorhanden sind, sollte nur eine Kombination mit text3 NOT NULL übrig bleiben. Beispiel:
1 | abc | def | NULL
2 | abc | def | ghi
3 | abc | def | jkl
4 | aaa | bbb | NULL
5 | aaa | bbb | NULL
...wird:
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)
Neue IDs sind alles kalt, sie hängen nicht von alten Tabellen-IDs ab.
Ich habe Dinge ausprobiert wie:
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;
Oder SELECT DISTINCT und andere Variationen.
Während sie an kleinen Datenbanken arbeiten, ist die Ausführungszeit für Abfragen bei mir einfach riesig (eigentlich nie bis zum Ende;> 20 Minuten)
Gibt es einen schnelleren Weg, das zu tun? Bitte helfen Sie mir, dieses Problem zu lösen.
quelle
Antworten:
Ich glaube, das wird es schaffen, wenn Sie einen doppelten Schlüssel + ifnull () verwenden:
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;
Sollte viel schneller sein als alles, was eine Gruppierung nach oder eine Unterabfrage oder sogar eine Bestellung nach erfordert. Dies erfordert nicht einmal einen Dateisort, der die Leistung einer großen temporären Tabelle beeinträchtigt. Erfordert immer noch einen vollständigen Scan der Originaltabelle, aber das lässt sich nicht vermeiden.
quelle
Ich habe diesen einfachen einzeiligen Code gefunden, um genau das zu tun, was ich brauchte:
ALTER IGNORE TABLE dupTest ADD UNIQUE INDEX(a,b);
Entnommen aus: http://mediakey.dk/~cc/mysql-remove-duplicate-entries/
quelle
IGNORE
Teil) funktioniert: Fehlercode: 1062 Doppelter Eintrag 'abc-def' für Schlüssel 'text1'set session old_alter_table=1
wenn Sie diesen Fehler erhalten, und es dann erneut versuchen.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 )
Dadurch werden alle Datensätze, Gruppen nach Unterscheidungsfeldern und Bestellungen nach ID abgefragt (dh wir wählen den ersten nicht null text3-Datensatz aus). Dann wählen wir die IDs aus diesem Ergebnis aus (dies sind gute IDs ... sie werden nicht gelöscht) und löschen alle IDs, die NICHT diese sind.
Eine solche Abfrage, die sich auf die gesamte Tabelle auswirkt, ist langsam. Sie müssen es nur ausführen und ausrollen lassen, damit Sie es in Zukunft verhindern können.
Nachdem Sie dieses "Update" durchgeführt haben, würde ich UNIQUE INDEX (text1, text2) auf diese Tabelle anwenden. Um die Möglichkeit von Duplikaten in Zukunft zu verhindern.
Wenn Sie die Route "Neue Tabelle erstellen und alte ersetzen" verwenden möchten. Sie können die sehr innere select-Anweisung verwenden, um Ihre insert-Anweisung zu erstellen.
MySQL-spezifisch (vorausgesetzt, die neue Tabelle heißt my_tbl2 und hat genau die gleiche Struktur):
INSERT INTO my_tbl2 SELECT DISTINCT id, text1, text2, text3 FROM dups GROUP BY text1, text2 ORDER BY text3 DESC
Siehe MySQL INSERT ... SELECTWeitere Informationen finden .
quelle
Entfernen Sie Duplikate, ohne Fremdschlüssel zu entfernen
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);
quelle
Wenn Sie eine neue Tabelle erstellen können, verwenden Sie dazu einen eindeutigen Schlüssel in den Feldern text1 + text2. Fügen Sie dann Fehler in die Tabelle ein (unter Verwendung der INSERT IGNORE-Syntax):
select * from my_tbl order by text3 desc
Indizes für all diese Spalten könnten viel helfen, aber das Erstellen könnte jetzt ziemlich langsam sein.
quelle
Bei großen Tabellen mit wenigen Duplikaten möchten Sie möglicherweise vermeiden, die gesamte Tabelle an einen anderen Ort zu kopieren. Eine Möglichkeit besteht darin, eine temporäre Tabelle mit den Zeilen zu erstellen, die Sie behalten möchten (für jeden Schlüssel mit Duplikaten), und dann Duplikate aus der Originaltabelle zu löschen.
Ein Beispiel wird hier gegeben .
quelle
Ich habe nicht viel Erfahrung mit MySQL. Wenn es analytische Funktionen hat, versuchen Sie:
Die optionale where-Klausel bedeutet, dass Sie sie mehrmals ausführen müssen, eine für jeden Buchstaben usw. Erstellen Sie einen Index für text1?
Vergewissern Sie sich vor dem Ausführen, dass "text desc" die letzten Nullen in MySQL sortiert.
quelle
Ich weiß, dass dies ein alter Thread ist, aber ich habe eine etwas chaotische Methode, die viel schneller und anpassbar ist. In Bezug auf die Geschwindigkeit würde ich 10 Sekunden anstelle von 100 Sekunden (10: 1) sagen.
Meine Methode erfordert all das chaotische Zeug, das Sie vermeiden wollten:
Aber wenn Sie über MILLIONEN (oder in meinem Fall Zehn Millionen) sprechen, lohnt es sich.
Trotzdem ist es nicht viel, weil die Kommentare auf Portugiesisch sind, aber hier ist mein Beispiel:
EDIT : Wenn ich Kommentare bekomme, erkläre ich weiter, wie es funktioniert :)
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;
quelle
Mit dieser einfachen Abfrage können Sie alle doppelten Einträge entfernen. Dadurch werden alle doppelten Datensätze ausgewählt und entfernt.
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
quelle