执行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: 两个都REPLACE
和INSERT...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 |
+----+------+