Polecam użycie INSERT...ON DUPLICATE KEY UPDATE
.
Jeśli używasz INSERT IGNORE
, wiersz nie zostanie faktycznie wstawiony, jeśli spowoduje to zduplikowanie klucza. Ale oświadczenie nie wygeneruje błędu. Zamiast tego generuje ostrzeżenie. Te przypadki obejmują:
- Wstawianie zduplikowanego klucza w kolumnach z
PRIMARY KEY
lubUNIQUE
ograniczenia. - Wstawianie NULL do kolumny z
NOT NULL
ograniczenie. - Wstawianie wiersza do tabeli podzielonej na partycje, ale wstawiane wartości nie są mapowane na partycję.
Jeśli używasz REPLACE
, MySQL faktycznie wykonuje DELETE
po którym następuje INSERT
wewnętrznie, co ma kilka nieoczekiwanych skutków ubocznych:
- Przydzielono nowy identyfikator automatycznego przyrostu.
- Zależne wiersze z kluczami obcymi mogą zostać usunięte (jeśli używasz kaskadowych kluczy obcych) lub uniemożliwić
REPLACE
. - Wyzwalacze uruchamiane po
DELETE
są niepotrzebnie wykonywane. - Efekty uboczne są również propagowane do replik.
korekta: oba REPLACE
i INSERT...ON DUPLICATE KEY UPDATE
są niestandardowymi, zastrzeżonymi wynalazkami specyficznymi dla MySQL. ANSI SQL 2003 definiuje MERGE
oświadczenie, które może rozwiązać tę samą potrzebę (i więcej), ale MySQL nie obsługuje MERGE
oświadczenie.
Użytkownik próbował edytować ten post (modyfikacja została odrzucona przez moderatorów). Edycja próbowała dodać roszczenie, które INSERT...ON DUPLICATE KEY UPDATE
powoduje przydzielenie nowego identyfikatora automatycznego przyrostu. To prawda, że nowy identyfikator jest generowany , ale nie jest używany w zmienionym wierszu.
Zobacz demonstrację poniżej, przetestowaną z Percona Server 5.5.28. Zmienna konfiguracyjna innodb_autoinc_lock_mode=1
(domyślnie):
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
Powyższe pokazuje, że instrukcja IODKU wykrywa duplikat i wywołuje aktualizację, aby zmienić wartość u
. Zwróć uwagę na AUTO_INCREMENT=3
wskazuje, że identyfikator został wygenerowany, ale nie został użyty w wierszu.
Natomiast REPLACE
usuwa oryginalny wiersz i wstawia nowy wiersz, generując i przechowywanie nowego identyfikatora automatycznego przyrostu:
mysql> select * from foo;
+----+------+
| id | u |
+----+------+
| 1 | 20 |
+----+------+
mysql> replace into foo (u) values (20);
mysql> select * from foo;
+----+------+
| id | u |
+----+------+
| 3 | 20 |
+----+------+