La suppression des doublons sur les tables MySQL est un problème courant, c'est généralement le résultat d'une contrainte manquante pour éviter ces doublons à l'avance. Mais ce problème commun s'accompagne généralement de besoins spécifiques ... qui nécessitent des approches spécifiques. L'approche doit être différente selon, par exemple, la taille des données, l'entrée dupliquée qui doit être conservée (généralement la première ou la dernière), s'il y a des index à conserver ou si nous voulons effectuer des action sur les données dupliquées.
Il existe également certaines spécificités sur MySQL lui-même, comme le fait de ne pas pouvoir référencer la même table sur une cause FROM lors de l'exécution d'une mise à jour de table (cela soulèvera l'erreur MySQL # 1093). Cette limitation peut être surmontée en utilisant une requête interne avec une table temporaire (comme suggéré dans certaines approches ci-dessus). Mais cette requête interne ne fonctionnera pas particulièrement bien lorsqu'il s'agit de sources de données volumineuses.
Cependant, il existe une meilleure approche pour supprimer les doublons, à la fois efficace et fiable, et qui peut être facilement adaptée à différents besoins.
L'idée générale est de créer une nouvelle table temporaire, en ajoutant généralement une contrainte unique pour éviter d'autres doublons, et d'insérer les données de votre ancienne table dans la nouvelle, tout en prenant soin des doublons. Cette approche repose sur des requêtes MySQL INSERT simples, crée une nouvelle contrainte pour éviter d'autres doublons, et ignore la nécessité d'utiliser une requête interne pour rechercher des doublons et une table temporaire qui doit être conservée en mémoire (s'adaptant ainsi également aux sources de Big Data).
Voilà comment cela peut être réalisé. Étant donné que nous avons un employé de table , avec les colonnes suivantes:
employee (id, first_name, last_name, start_date, ssn)
Afin de supprimer les lignes avec une colonne ssn en double et en ne conservant que la première entrée trouvée, le processus suivant peut être suivi:
-- 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;
Explication technique
- La ligne # 1 crée une nouvelle table tmp_eployee avec exactement la même structure que la table des employés
- La ligne # 2 ajoute une contrainte UNIQUE à la nouvelle table tmp_eployee pour éviter tout doublon supplémentaire
- La ligne n ° 3 parcourt la table des employés d' origine par identifiant, en insérant de nouvelles entrées d'employé dans la nouvelle table tmp_eployee , tout en ignorant les entrées en double
- La ligne # 4 renomme les tables, de sorte que la nouvelle table des employés contienne toutes les entrées sans les doublons, et une copie de sauvegarde des anciennes données est conservée dans la table backup_employee
⇒ En utilisant cette approche, 1,6M de registres ont été convertis en 6k en moins de 200s.
Chetan , en suivant ce processus, vous pouvez supprimer rapidement et facilement tous vos doublons et créer une contrainte UNIQUE en exécutant:
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;
Bien sûr, ce processus peut être modifié pour l'adapter aux différents besoins lors de la suppression des doublons. Quelques exemples suivent.
✔ Variation pour conserver la dernière entrée au lieu de la première
Parfois, nous devons conserver la dernière entrée dupliquée au lieu de la première.
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;
- Sur la ligne # 3, la clause ORDER BY id DESC fait que les derniers ID obtiennent la priorité sur les autres
✔ Variation pour effectuer certaines tâches sur les doublons, par exemple en comptant les doublons trouvés
Parfois, nous devons effectuer un traitement supplémentaire sur les entrées dupliquées trouvées (par exemple, en comptant les doublons).
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;
- Sur la ligne # 3, une nouvelle colonne n_duplicates est créée
- Sur la ligne # 4, la requête INSERT INTO ... ON DUPLICATE KEY UPDATE est utilisée pour effectuer une mise à jour supplémentaire lorsqu'un doublon est trouvé (dans ce cas, l'augmentation d'un compteur) La requête INSERT INTO ... ON DUPLICATE KEY UPDATE peut être utilisé pour effectuer différents types de mises à jour pour les doublons trouvés.
✔ Variation pour régénérer l'identifiant de champ auto-incrémental
Parfois, nous utilisons un champ auto-incrémentiel et, afin de garder l'index aussi compact que possible, nous pouvons profiter de la suppression des doublons pour régénérer le champ auto-incrémental dans la nouvelle table temporaire.
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;
- Sur la ligne n ° 3, au lieu de sélectionner tous les champs de la table, le champ id est ignoré afin que le moteur de base de données en génère automatiquement un nouveau
✔ Autres variations
De nombreuses autres modifications sont également réalisables en fonction du comportement souhaité. À titre d'exemple, les requêtes suivantes utiliseront une deuxième table temporaire pour, outre 1) conserver la dernière entrée au lieu de la première; et 2) augmenter le compteur des doublons trouvés; également 3) régénérer l'identifiant de champ auto-incrémentiel tout en conservant l'ordre d'entrée tel qu'il était sur les anciennes données.
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;