Mysql
 sql >> Base de Dados >  >> RDS >> Mysql

INSERT IGNORE vs INSERT ... ON DUPLICATE KEY UPDATE


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 ou UNIQUE 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 |
+----+------+