Das Löschen von Duplikaten in MySQL-Tabellen ist ein häufiges Problem. Dies ist im Allgemeinen das Ergebnis einer fehlenden Einschränkung, um diese Duplikate vorab zu vermeiden. Dieses häufig auftretende Problem ist jedoch in der Regel mit spezifischen Anforderungen verbunden, die bestimmte Ansätze erfordern. Der Ansatz sollte unterschiedlich sein, abhängig beispielsweise von der Größe der Daten, dem doppelten Eintrag, der beibehalten werden soll (im Allgemeinen der erste oder der letzte), ob Indizes beibehalten werden müssen oder ob zusätzliche Änderungen vorgenommen werden sollen Aktion auf die duplizierten Daten.
Es gibt auch einige Besonderheiten in MySQL selbst, z. B., dass beim Ausführen eines Tabellen-UPDATE nicht auf dieselbe Tabelle in einer FROM-Ursache verwiesen werden kann (dies führt zu MySQL-Fehler Nr. 1093). Diese Einschränkung kann überwunden werden, indem eine innere Abfrage mit einer temporären Tabelle verwendet wird (wie bei einigen Ansätzen oben vorgeschlagen). Diese innere Abfrage funktioniert jedoch beim Umgang mit Big-Data-Quellen nicht besonders gut.
Es gibt jedoch einen besseren Ansatz zum Entfernen von Duplikaten, der sowohl effizient als auch zuverlässig ist und leicht an unterschiedliche Anforderungen angepasst werden kann.
Die allgemeine Idee besteht darin, eine neue temporäre Tabelle zu erstellen, in der Regel eine eindeutige Einschränkung hinzuzufügen, um weitere Duplikate zu vermeiden, und die Daten aus Ihrer früheren Tabelle in die neue einzufügen, während Sie sich um die Duplikate kümmern. Dieser Ansatz basiert auf einfachen MySQL INSERT-Abfragen, erstellt eine neue Einschränkung, um weitere Duplikate zu vermeiden, und überspringt die Verwendung einer inneren Abfrage zur Suche nach Duplikaten und einer temporären Tabelle, die im Speicher aufbewahrt werden sollte (wodurch auch große Datenquellen angepasst werden).
So kann es erreicht werden. Gegeben wir einen Tisch haben Mitarbeiter , mit den folgenden Spalten:
employee (id, first_name, last_name, start_date, ssn)
Um die Zeilen mit einer doppelten SSN- Spalte zu löschen und nur den ersten gefundenen Eintrag beizubehalten , kann der folgende Vorgang ausgeführt werden:
-- create a new tmp_eployee table
CREATE TABLE tmp_employee LIKE employee;
-- add a unique constraint
ALTER TABLE tmp_employee ADD UNIQUE(ssn);
-- scan over the employee table to insert employee entries
INSERT IGNORE INTO tmp_employee SELECT * FROM employee ORDER BY id;
-- rename tables
RENAME TABLE employee TO backup_employee, tmp_employee TO employee;
Technische Erklärung
- Linie # 1 erstellt eine neue tmp_eployee Tabelle mit genau der gleichen Struktur wie die Mitarbeiter Tabelle
- Zeile 2 fügt der neuen Tabelle tmp_eployee eine EINZIGARTIGE Einschränkung hinzu , um weitere Duplikate zu vermeiden
- Zeile 3 durchsucht die ursprüngliche Mitarbeitertabelle nach ihrer ID, fügt neue Mitarbeitereinträge in die neue Tabelle tmp_eployee ein und ignoriert doppelte Einträge
- In Zeile 4 werden Tabellen umbenannt, sodass die neue Mitarbeitertabelle alle Einträge ohne die Duplikate enthält und eine Sicherungskopie der früheren Daten in der Tabelle backup_employee gespeichert wird
⇒ Mit diesem Ansatz wurden 1,6 Millionen Register in weniger als 200 Sekunden in 6 KB konvertiert.
Chetan : Nach diesem Vorgang können Sie schnell und einfach alle Ihre Duplikate entfernen und eine EINZIGARTIGE Einschränkung erstellen, indem Sie Folgendes ausführen:
CREATE TABLE tmp_jobs LIKE jobs;
ALTER TABLE tmp_jobs ADD UNIQUE(site_id, title, company);
INSERT IGNORE INTO tmp_jobs SELECT * FROM jobs ORDER BY id;
RENAME TABLE jobs TO backup_jobs, tmp_jobs TO jobs;
Natürlich kann dieser Prozess weiter modifiziert werden, um ihn beim Löschen von Duplikaten an unterschiedliche Anforderungen anzupassen. Es folgen einige Beispiele.
✔ Variation zum Beibehalten des letzten Eintrags anstelle des ersten
Manchmal müssen wir den letzten duplizierten Eintrag anstelle des ersten behalten.
CREATE TABLE tmp_employee LIKE employee;
ALTER TABLE tmp_employee ADD UNIQUE(ssn);
INSERT IGNORE INTO tmp_employee SELECT * FROM employee ORDER BY id DESC;
RENAME TABLE employee TO backup_employee, tmp_employee TO employee;
- In Zeile 3 bewirkt die ORCER BY id DESC- Klausel, dass die letzten IDs Vorrang vor den anderen haben
✔ Variation zum Ausführen einiger Aufgaben für die Duplikate, z. B. Zählen der gefundenen Duplikate
Manchmal müssen wir die gefundenen duplizierten Einträge weiter verarbeiten (z. B. die Anzahl der duplizierten Einträge beibehalten).
CREATE TABLE tmp_employee LIKE employee;
ALTER TABLE tmp_employee ADD UNIQUE(ssn);
ALTER TABLE tmp_employee ADD COLUMN n_duplicates INT DEFAULT 0;
INSERT INTO tmp_employee SELECT * FROM employee ORDER BY id ON DUPLICATE KEY UPDATE n_duplicates=n_duplicates+1;
RENAME TABLE employee TO backup_employee, tmp_employee TO employee;
- In Zeile 3 wird eine neue Spalte n_duplicates erstellt
- In Zeile 4 wird die Abfrage INSERT INTO ... ON DUPLICATE KEY UPDATE verwendet, um eine zusätzliche Aktualisierung durchzuführen, wenn ein Duplikat gefunden wird (in diesem Fall wird ein Zähler erhöht). Die Abfrage INSERT INTO ... ON DUPLICATE KEY UPDATE kann sein wird verwendet, um verschiedene Arten von Aktualisierungen für die gefundenen Duplikate durchzuführen.
✔ Variation zum Regenerieren der automatisch inkrementellen Feld-ID
Manchmal verwenden wir ein automatisch inkrementelles Feld. Um den Index so kompakt wie möglich zu halten, können wir das Löschen der Duplikate nutzen, um das automatisch inkrementelle Feld in der neuen temporären Tabelle neu zu generieren.
CREATE TABLE tmp_employee LIKE employee;
ALTER TABLE tmp_employee ADD UNIQUE(ssn);
INSERT IGNORE INTO tmp_employee SELECT (first_name, last_name, start_date, ssn) FROM employee ORDER BY id;
RENAME TABLE employee TO backup_employee, tmp_employee TO employee;
- In Zeile 3 wird das ID-Feld übersprungen, anstatt alle Felder in der Tabelle auszuwählen, sodass die DB-Engine automatisch ein neues generiert
✔ Weitere Variationen
Abhängig vom gewünschten Verhalten sind auch viele weitere Modifikationen möglich. In den folgenden Abfragen wird beispielsweise eine zweite temporäre Tabelle verwendet, um neben 1) den letzten Eintrag anstelle des ersten zu behalten; und 2) einen Zähler für die gefundenen Duplikate erhöhen; auch 3) Generieren Sie die automatisch inkrementelle Feld-ID neu, während Sie die Eingabereihenfolge wie bei den vorherigen Daten beibehalten.
CREATE TABLE tmp_employee LIKE employee;
ALTER TABLE tmp_employee ADD UNIQUE(ssn);
ALTER TABLE tmp_employee ADD COLUMN n_duplicates INT DEFAULT 0;
INSERT INTO tmp_employee SELECT * FROM employee ORDER BY id DESC ON DUPLICATE KEY UPDATE n_duplicates=n_duplicates+1;
CREATE TABLE tmp_employee2 LIKE tmp_employee;
INSERT INTO tmp_employee2 SELECT (first_name, last_name, start_date, ssn) FROM tmp_employee ORDER BY id;
DROP TABLE tmp_employee;
RENAME TABLE employee TO backup_employee, tmp_employee2 TO employee;