Je recommanderais d'utiliser INSERT...ON DUPLICATE KEY UPDATE
.
Si vous utilisez INSERT IGNORE
, la ligne ne sera pas réellement insérée si elle aboutit à une clé en double. Mais l'instruction ne générera pas d'erreur. Il génère à la place un avertissement. Ces cas comprennent:
- Insertion d'une clé en double dans les colonnes avec
PRIMARY KEY
ou UNIQUE
contraintes.
- Insertion d'un NULL dans une colonne avec une
NOT NULL
contrainte.
- Insertion d'une ligne dans une table partitionnée, mais les valeurs que vous insérez ne sont pas mappées sur une partition.
Si vous utilisez REPLACE
, MySQL fait en fait un DELETE
suivi d'un INSERT
interne, ce qui a des effets secondaires inattendus:
- Un nouvel ID d'incrémentation automatique est alloué.
- Les lignes dépendantes avec des clés étrangères peuvent être supprimées (si vous utilisez des clés étrangères en cascade) ou bien empêcher le
REPLACE
.
- Les déclencheurs qui se déclenchent
DELETE
sont exécutés inutilement.
- Les effets secondaires se propagent également aux répliques.
correction: les deux REPLACE
et INSERT...ON DUPLICATE KEY UPDATE
sont des inventions propriétaires non standard, spécifiques à MySQL. ANSI SQL 2003 définit une MERGE
instruction qui peut résoudre le même besoin (et plus), mais MySQL ne prend pas en charge l' MERGE
instruction.
Un utilisateur a tenté de modifier cette publication (la modification a été rejetée par les modérateurs). La modification a tenté d'ajouter une revendication qui INSERT...ON DUPLICATE KEY UPDATE
provoque l'attribution d'un nouvel identifiant d'incrémentation automatique. Il est vrai que le nouvel identifiant est généré , mais il n'est pas utilisé dans la ligne modifiée.
Voir la démonstration ci-dessous, testée avec Percona Server 5.5.28. La variable de configuration innodb_autoinc_lock_mode=1
(par défaut):
mysql> create table foo (id serial primary key, u int, unique key (u));
mysql> insert into foo (u) values (10);
mysql> select * from foo;
+----+------+
| id | u |
+----+------+
| 1 | 10 |
+----+------+
mysql> show create table foo\G
CREATE TABLE `foo` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`u` int(11) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `u` (`u`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=latin1
mysql> insert into foo (u) values (10) on duplicate key update u = 20;
mysql> select * from foo;
+----+------+
| id | u |
+----+------+
| 1 | 20 |
+----+------+
mysql> show create table foo\G
CREATE TABLE `foo` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`u` int(11) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `u` (`u`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=latin1
Ce qui précède montre que l'instruction IODKU détecte le doublon et appelle la mise à jour pour modifier la valeur de u
. Notez que AUTO_INCREMENT=3
indique qu'un identifiant a été généré, mais n'est pas utilisé dans la ligne.
Alors REPLACE
que supprime la ligne d'origine et insère une nouvelle ligne, la génération et le stockage d'un nouvel identifiant d'incrémentation automatique:
mysql> select * from foo;
+----+------+
| id | u |
+----+------+
| 1 | 20 |
+----+------+
mysql> replace into foo (u) values (20);
mysql> select * from foo;
+----+------+
| id | u |
+----+------+
| 3 | 20 |
+----+------+
INSERT ... ON DUPLICATE KEY UPDATE ...
déclarations. Beaucoup de données sont en double, et il en est résulté une instance de l'IA PK passant de 17 029 941 à 46 271 740 entre deux lignes. Cette génération d'une nouvelle IA à chaque fois signifie que votre gamme peut être très rapidement remplie et que vous devez nettoyer. Cette table n'a que deux semaines!Au cas où vous voudriez voir ce que tout cela signifie, voici un coup par coup de tout:
La clé primaire est basée sur les deux colonnes de ce tableau de référence rapide. Une clé primaire nécessite des valeurs uniques.
Commençons:
notez que ce qui précède a sauvé trop de travail supplémentaire en définissant la colonne égale à elle-même, aucune mise à jour réellement nécessaire
et maintenant quelques tests sur plusieurs lignes:
aucun autre message n'a été généré dans la console, et elle a maintenant ces 4 valeurs dans les données de la table. J'ai tout supprimé sauf (1,1) pour pouvoir tester à partir du même terrain de jeu
Alors voilà. Étant donné que tout cela a été effectué sur une nouvelle table avec presque aucune donnée et pas en production, les délais d'exécution étaient microscopiques et non pertinents. Toute personne disposant de données réelles serait plus que bienvenue à les fournir.
la source
INSERT IGNORE INTO users_partners (uid,pid) VALUES (1,1),(1,2),(1,3),(1,4)
.Quelque chose d'important à ajouter: lorsque vous utilisez INSERT IGNORE et que vous avez des violations de clés, MySQL ne déclenche PAS d'avertissement!
Si vous essayez par exemple d'insérer 100 enregistrements à la fois, dont un défectueux, vous obtiendrez en mode interactif:
Comme vous le voyez: aucun avertissement! Ce comportement est même décrit à tort dans la documentation officielle de Mysql.
Si votre script doit être informé, si certains enregistrements n'ont pas été ajoutés (en raison de violations de clés), vous devez appeler mysql_info () et l'analyser pour la valeur "Duplicates".
la source
mysqli_affected_rows()
de savoir siINSERT
cela s'est réellement produit.Cannot add or update a child row: a foreign key constraint fails
et aucune ligne (même valide) n'est ajoutée.INSERT IGNORE
, les clés en double sont ignorées sans erreur ni avertissement.J'utilise régulièrement
INSERT IGNORE
, et cela ressemble exactement au type de comportement que vous recherchez également. Tant que vous savez que les lignes qui provoqueraient des conflits d'index ne seront pas insérées et que vous planifiez votre programme en conséquence, cela ne devrait causer aucun problème.la source
Je sais que c'est ancien, mais j'ajouterai cette note au cas où quelqu'un d'autre (comme moi) arriverait sur cette page en essayant de trouver des informations sur INSERT..IGNORE.
Comme mentionné ci-dessus, si vous utilisez INSERT..IGNORE, les erreurs qui se produisent lors de l'exécution de l'instruction INSERT sont traitées comme des avertissements à la place.
Une chose qui n'est pas explicitement mentionnée est que INSERT..IGNORE entraînera des valeurs invalides seront ajustées aux valeurs les plus proches lors de l'insertion (alors que des valeurs invalides entraîneraient l'abandon de la requête si le mot clé IGNORE n'était pas utilisé).
la source
ON DUPLICATE KEY UPDATE n'est pas vraiment dans la norme. C'est à peu près aussi standard que REMPLACER. Voir SQL MERGE .
Les deux commandes sont essentiellement des versions à syntaxe alternative des commandes standard.
la source
Replace
En semble être une option. Ou vous pouvez vérifier avecCela va insérer ou supprimer puis insérer. J'ai tendance à faire un
IF NOT EXISTS
chèque en premier.la source
REPLACE
supprime toutes les lignes de la table avec correspondance toutPRIMARY
ouUNIQUE
clé, puisINSERTs
. C'est potentiellement beaucoup plus de travail que IODKU.Danger potentiel d'INSERER IGNORE. Si vous essayez d'insérer une valeur VARCHAR plus longtemps, la colonne a été définie avec - la valeur sera tronquée et insérée MÊME SI le mode strict est activé.
la source
Si vous utilisez
insert ignore
uneSHOW WARNINGS;
instruction à la fin de votre ensemble de requêtes, un tableau affiche tous les avertissements, y compris les ID qui étaient les doublons.la source
SHOW WARNINGS;
ne semble affecter que la dernière requête. Les relevés précédents ne sont pas cumulés, si vous en avez plusieurs.Si vous souhaitez insérer dans la table et sur le conflit de la clé primaire ou de l'index unique, il mettra à jour la ligne en conflit au lieu d'insérer cette ligne.
Syntaxe:
Maintenant, ici, cette instruction d'insertion peut différer de ce que vous avez vu précédemment. Cette instruction d'insertion tente d'insérer une ligne dans le tableau1 avec la valeur de a et b dans la colonne colonne1 et colonne2 respectivement.
Comprenons cette déclaration en profondeur:
Par exemple: ici column1 est défini comme la clé primaire dans table1.
Maintenant, si dans le tableau 1, aucune ligne n'a la valeur «a» dans la colonne 1. Cette instruction insérera donc une ligne dans la table1.
Maintenant, si dans le tableau 1, il y a une ligne ayant la valeur «a» dans la colonne 2. Ainsi, cette instruction mettra à jour la valeur column2 de la ligne avec «c» où la valeur column1 est «a».
Donc, si vous souhaitez insérer une nouvelle ligne, sinon mettez à jour cette ligne sur le conflit de la clé primaire ou de l'index unique.
En savoir plus sur ce lien
la source
INSERT...ON DUPLICATE KEY UPDATE
est préférable pour éviter la gestion des exceptions inattendues.Cette solution fonctionne lorsque vous avez ** 1 contrainte unique ** uniquement
Dans mon cas, je le sais
col1
et je créecol2
un index composite unique.Il garde la trace de l'erreur, mais ne lance pas d'exception sur les doublons. En ce qui concerne les performances, la mise à jour de la même valeur est efficace car MySQL le remarque et ne la met pas à jour
L'idée d'utiliser cette approche est venue des commentaires sur phpdelusions.net/pdo .
la source