web-dev-qa-db-fra.com

Suppression des doublons avec un index unique

J'ai inséré entre deux tables les champs A, B, C, D, croyant avoir créé un index unique sur A, B, C, D pour éviter les doublons. Cependant j'ai en quelque sorte simplement fait un index normal sur ceux-ci. Des doublons ont donc été insérés. C'est une table record de 20 millions.

Si je change mon index existant de normal à unique ou simplement ajoute un nouvel index unique pour A, B, C, D, les doublons seront-ils supprimés ou l'ajout échouera-t-il car des enregistrements uniques existent? Je le testerais pourtant, il s'agit de disques de 30 mil et je ne souhaite ni gâcher la table ni la dupliquer.

17
user3649739

Si vous avez des doublons dans votre table et que vous utilisez

ALTER TABLE mytable ADD UNIQUE INDEX myindex (A, B, C, D);

la requête échouera avec l'erreur 1062 (clé en double).

Mais si vous utilisez IGNORE

-- (only works before MySQL 5.7.4)
ALTER IGNORE TABLE mytable ADD UNIQUE INDEX myindex (A, B, C, D);

les doublons seront supprimés. Mais la documentation ne précise pas quelle ligne sera conservée:

  • IGNORE est une extension MySQL du SQL standard. Il contrôle comment ALTER TABLE fonctionne s'il y a des doublons sur des clés uniques dans la nouvelle table ou si des avertissements se produisent lorsque le mode strict est activé. Si IGNORE n'est pas spécifié, la copie est abandonnée et annulée si des erreurs de clé en double se produisent. Si IGNORE est spécifié, une seule ligne est utilisée pour les lignes avec doublons sur une clé unique. Les autres lignes en conflit sont supprimées. Les valeurs incorrectes sont tronquées à la valeur acceptable correspondante la plus proche.

    Depuis MySQL 5.7.4, la clause IGNORE pour ALTER TABLE est supprimée et son utilisation génère une erreur.

( Syntaxe ALTER TABLE )

Si votre version est 5.7.4 ou supérieure - vous pouvez:

  • Copiez les données dans une table temporaire (elle n'a pas besoin techniquement d'être temporaire).
  • Tronquez la table d'origine.
  • Créez l'INDEX UNIQUE.
  • Et copiez les données avec INSERT IGNORE (qui est toujours disponible).
CREATE TABLE tmp_data SELECT * FROM mytable;
TRUNCATE TABLE mytable;
ALTER TABLE mytable ADD UNIQUE INDEX myindex (A, B, C, D);
INSERT IGNORE INTO mytable SELECT * from tmp_data;
DROP TABLE tmp_data;

Si vous utilisez le modificateur IGNORE, les erreurs qui se produisent lors de l'exécution de l'instruction INSERT sont ignorées. Par exemple, sans IGNORE, une ligne qui duplique un index UNIQUE ou PRIMARY KEY la valeur dans le tableau provoque une erreur de clé en double et l'instruction est abandonnée. Avec IGNORE, la ligne est supprimée et aucune erreur ne se produit. Les erreurs ignorées génèrent à la place des avertissements.

(INSÉRER la syntaxe)

Voir aussi: INSERT ... SELECT Syntax et Comparaison du mot-clé IGNORE et du mode SQL strict

53
Paul Spiegel

si vous pensez qu'il y aura des doublons, l'ajout de l'index unique échouera. vérifiez d'abord les doublons:

select * from
(select a,b,c,d,count(*) as n from table_name group by a,b,c,d) x
where x.n > 1

Cela peut être une requête coûteuse sur 20 millions de lignes, mais vous obtiendrez toutes les clés en double qui vous empêcheront d'ajouter l'index principal. Vous pouvez le diviser en morceaux plus petits si vous faites un où dans la sous-requête: where a='some_value'

Pour les enregistrements récupérés, vous devrez modifier quelque chose pour rendre les lignes uniques. Si cela est fait (la requête renvoie 0 lignes), vous devriez être sûr d'ajouter l'index principal.

4
verhie

Au lieu d'IGNORE, vous pouvez utiliser ON DUPLICATE KEY UPDATE, qui vous donnera le contrôle sur les valeurs qui doivent prévaloir.

2
Oriol Vilaseca

Pour répondre à votre question, l'ajout d'une contrainte UNIQUE sur une colonne contenant des valeurs en double génère une erreur.

Par exemple, vous pouvez essayer le script suivant:

CREATE TABLE `USER` (
  `USER_ID` INT NOT NULL,
  `USERNAME` VARCHAR(45) NOT NULL,
  `NAME` VARCHAR(45) NULL,
  PRIMARY KEY (`USER_ID`));

INSERT INTO USER VALUES(1,'Apple', 'woz'),(2,'Apple', 'jobs'),
(3,'google', 'sergey'),(4,'google', 'larry');

ALTER TABLE `USER` 
ADD UNIQUE INDEX `USERNAME_UNIQUE` (`USERNAME` ASC);
/*
Operation failed: There was an error while applying the SQL script to the database.
ERROR 1062: Duplicate entry 'Apple' for key 'USERNAME_UNIQUE'
*/
0
Sarath Chandra