执行INSERT用许多行声明,我想跳过重复的条目,这些条目原本会导致故障。经过一些研究,我的选择似乎是使用:

  • ON DUPLICATE KEY UPDATE这意味着不必要的更新,或者
  • INSERT IGNORE意味着其他类型的失败会在未经通知的情况下溜进来。

我在这些假设中是对的吗?简单地跳过可能导致重复并继续前进的行的行的最佳方法是什么?

答案

我建议使用INSERT...ON DUPLICATE KEY UPDATE

如果您使用INSERT IGNORE,如果该行导致重复键,则实际上不会插入该行。但是该语句不会产生错误。它会产生警告。这些案例包括:

  • 将重复键插入与PRIMARY KEY或者UNIQUE限制。
  • 将null插入与NOT NULL约束。
  • 向分区表插入一行,但插入的值不映射到分区。

如果您使用REPLACE,mysql实际上做了DELETE然后是INSERT内部有一些意想不到的副作用:

  • 分配新的自增ID。
  • 可能会删除带有外国钥匙的依赖行(如果您使用级联的外键),否则可以防止REPLACE
  • 触发发射的DELETE不必要地执行。
  • 副作用也被传播到复制品。

correction: 两个都REPLACEINSERT...ON DUPLICATE KEY UPDATE是非标准的,专有的发明。ANSI SQL 2003定义了MERGE语句可以解决相同的需求(以及更多),但MySQL不支持MERGE陈述。


用户尝试编辑此帖子(编辑被版主拒绝)。INSERT...ON DUPLICATE KEY UPDATE导致新的自动收入ID被分配。的确,新ID是生成,但在更改的行中不使用它。

请参见下面的演示,使用Percona服务器进行测试5.5.28。配置变量innodb_autoinc_lock_mode=1(默认):

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

以上表明iodku语句检测到副本,并调用更新以更改的值u。注意AUTO_INCREMENT=3指示生成ID,但在行中未使用。

然而REPLACE是否删除原始行并插入新行,生成存储一个新的自动收入ID:

mysql> select * from foo;
+----+------+
| id | u    |
+----+------+
|  1 |   20 |
+----+------+
mysql> replace into foo (u) values (20);
mysql> select * from foo;
+----+------+
| id | u    |
+----+------+
|  3 |   20 |
+----+------+

来自: stackoverflow.com