Eu recomendaria usar
INSERT...ON DUPLICATE KEY UPDATE
. Se você usar
INSERT IGNORE
, a linha não será inserida se resultar em uma chave duplicada. Mas a instrução não gerará um erro. Em vez disso, gera um aviso. Esses casos incluem:- Inserindo uma chave duplicada em colunas com
PRIMARY KEY
ouUNIQUE
restrições. - Inserindo um NULL em uma coluna com um
NOT NULL
restrição. - Inserindo uma linha em uma tabela particionada, mas os valores inseridos não são mapeados para uma partição.
Se você usar
REPLACE
, o MySQL realmente faz um DELETE
seguido por um INSERT
internamente, que tem alguns efeitos colaterais inesperados:- Um novo ID de incremento automático é alocado.
- Linhas dependentes com chaves estrangeiras podem ser excluídas (se você usar chaves estrangeiras em cascata) ou então impedir o
REPLACE
. - Acionadores que disparam em
DELETE
são executados desnecessariamente. - Os efeitos colaterais também são propagados para réplicas.
correção: ambos
REPLACE
e INSERT...ON DUPLICATE KEY UPDATE
são invenções proprietárias não padronizadas específicas do MySQL. ANSI SQL 2003 define um MERGE
declaração que pode resolver a mesma necessidade (e mais), mas o MySQL não suporta o MERGE
demonstração. Um usuário tentou editar esta postagem (a edição foi rejeitada pelos moderadores). A edição tentou adicionar uma declaração que
INSERT...ON DUPLICATE KEY UPDATE
faz com que um novo id de incremento automático seja alocado. É verdade que o novo id é gerado , mas não é usado na linha alterada. Veja a demonstração abaixo, testada com o Percona Server 5.5.28. A variável de configuração
innodb_autoinc_lock_mode=1
(o padrão):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
O acima demonstra que a instrução IODKU detecta a duplicata e invoca a atualização para alterar o valor de
u
. Observe o AUTO_INCREMENT=3
indica que um id foi gerado, mas não usado na linha. Considerando que
REPLACE
exclui a linha original e insere uma nova linha, gerando e armazenando um novo id de incremento automático:mysql> select * from foo;
+----+------+
| id | u |
+----+------+
| 1 | 20 |
+----+------+
mysql> replace into foo (u) values (20);
mysql> select * from foo;
+----+------+
| id | u |
+----+------+
| 3 | 20 |
+----+------+