“ INSERT IGNORE”与“ INSERT…ON DUPLICATE KEY UPDATE”

在执行包含多行的INSERT语句时,我想跳过重复的条目,否则它们会导致失败。 经过研究后,我的选择似乎是使用以下任一方法:

  • ON DUPLICATE KEY UPDATE ,这意味着要付出一定的代价进行不必要的更新,或者
  • INSERT IGNORE ,这暗示了其他类型的失败通知。

这些假设对吗? 跳过可能导致重复的行并继续其他行的最佳方法是什么?


#1楼

我知道这很旧,但是我会添加此注释,以防其他人(例如我)在试图找到有关INSERT..IGNORE的信息时到达此页面。

如上所述,如果使用INSERT..IGNORE,则在执行INSERT语句时发生的错误将被视为警告。

没有明确提到的一件事是INSERT..IGNORE将导致无效值在插入时将调整为最接近的值(而无效值将导致查询中止(如果不使用IGNORE关键字)。


#2楼

如果使用insert ignore SHOW WARNINGS; 查询集末尾的语句将显示一个表,其中包含所有警告,包括哪些ID是重复的。


#3楼

INSERT IGNORE的潜在危险。 如果尝试插入VARCHAR值的时间更长,则使用-定义了列,该值将被截断,并且即使启用了严格模式也可以插入。


#4楼

如果要插入表中并且在主键或唯一索引冲突时,它将更新冲突的行,而不是插入该行。

句法:

insert into table1 set column1 = a, column2 = b on duplicate update column2 = c;

现在在这里,此插入语句可能看起来与您之前看到的有所不同。 该插入语句试图将table1中具有a和b值的行分别插入到column1和column2列中。

让我们深入了解以下语句:

例如:这里column1被定义为table1中的主键。

现在,如果在表1中,在列1中没有行具有值“ a”。 因此,该语句将在table1中插入一行。

现在,如果在表1中,在列2中存在一行具有值“ a”的行。 因此,此语句将使用“ c”更新行的column2值,其中column1值为“ a”。

因此,如果要插入新行,则在主键或唯一索引冲突时更新该行。
阅读更多有关此链接的信息


#5楼

Replace为似乎是一个选择。 或者你可以检查

IF NOT EXISTS(QUERY) Then INSERT

这将插入或删除,然后插入。 我倾向于先进行IF NOT EXISTS检查。


#6楼

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

如果使用INSERT IGNORE ,那么如果该行导致重复的键,则实际上不会插入该行。 但是该语句不会产生错误。 而是生成警告。 这些情况包括:

  • 在具有PRIMARY KEYUNIQUE约束的列中插入重复键。
  • 将NULL插入具有NOT NULL约束的列中。
  • 在分区表中插入一行,但是您插入的值不会映射到分区。

如果使用REPLACEMySQL实际上会在内部进行DELETE并随后INSERT ,这会有一些意外的副作用:

  • 分配了一个新的自动增量ID。
  • 带有外键的相关行可能会被删除(如果您使用级联外键),否则可能会导致无法REPLACE
  • 触发执行DELETE触发器是不必要的。
  • 副作用也传播到副本。

修正: REPLACEINSERT...ON DUPLICATE KEY UPDATE都是针对MySQL的非标准专有技术。 ANSI SQL 2003定义了一个MERGE语句,该语句可以解决相同的需求(甚至更多),但是MySQL不支持MERGE语句。


一位用户尝试编辑此帖子(主持人拒绝了该编辑)。 该编辑尝试添加一个声明,即INSERT...ON DUPLICATE KEY UPDATEINSERT...ON DUPLICATE KEY UPDATE会导致分配新的自动增量ID。 确实会生成新的id,但是更改后的行中不会使用它。

请参见下面的演示,该演示已通过Percona Server 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 |
+----+------+

#7楼

我通常使用INSERT IGNORE ,这听起来也正是您想要的行为。 只要您知道将不会插入会导致索引冲突的行,并据此计划程序,就不会造成任何麻烦。


#8楼

ON DUPLICATE KEY UPDATE并不是真正的标准。 它与REPLACE一样是标准的。 请参见SQL MERGE

本质上,这两个命令都是标准命令的替代语法版本。


#9楼

需要添加的重要信息:使用INSERT IGNORE时,如果确实存在键冲突,MySQL不会发出警告!

例如,如果您尝试一次插入100条记录,其中一条出现错误,则将进入交互模式:

Query OK, 99 rows affected (0.04 sec)

Records: 100 Duplicates: 1 Warnings: 0

如您所见:没有警告! 在官方的Mysql文档中甚至错误地描述了此行为。

如果需要通知脚本,如果未添加某些记录(由于键冲突),则必须调用mysql_info()并将其解析为“ Duplicates”值。


#10楼

INSERT...ON DUPLICATE KEY UPDATE来防止意外的异常管理。

仅当您具有** 1个唯一约束**时,此解决方案才有效

就我而言,我知道col1col2构成唯一的复合索引。

它跟踪错误,但不会在重复项上引发异常。 关于性能,以相同的值进行更新是有效的,因为MySQL注意到了这一点,并且不进行更新

INSERT INTO table
  (col1, col2, col3, col4)
VALUES
  (?, ?, ?, ?)
ON DUPLICATE KEY UPDATE
    col1 = VALUES(col1),
    col2 = VALUES(col2)

使用这种方法的想法来自phpdelusions.net/pdo的评论。


#11楼

如果您想了解所有这些内容,以下是所有内容的逐项记录:

CREATE TABLE `users_partners` (
  `uid` int(11) NOT NULL DEFAULT '0',
  `pid` int(11) NOT NULL DEFAULT '0',
  PRIMARY KEY (`uid`,`pid`),
  KEY `partner_user` (`pid`,`uid`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8

主键基于此快速参考表的两列。 主键需要唯一的值。

让我们开始:

INSERT INTO users_partners (uid,pid) VALUES (1,1);
...1 row(s) affected

INSERT INTO users_partners (uid,pid) VALUES (1,1);
...Error Code : 1062
...Duplicate entry '1-1' for key 'PRIMARY'

INSERT IGNORE INTO users_partners (uid,pid) VALUES (1,1);
...0 row(s) affected

INSERT INTO users_partners (uid,pid) VALUES (1,1) ON DUPLICATE KEY UPDATE uid=uid
...0 row(s) affected

请注意,以上方法通过将列设置为等于自身而节省了过多的额外工作,实际上无需更新

REPLACE INTO users_partners (uid,pid) VALUES (1,1)
...2 row(s) affected

现在进行一些多行测试:

INSERT INTO users_partners (uid,pid) VALUES (1,1),(1,2),(1,3),(1,4)
...Error Code : 1062
...Duplicate entry '1-1' for key 'PRIMARY'

INSERT IGNORE INTO users_partners (uid,pid) VALUES (1,1),(1,2),(1,3),(1,4)
...3 row(s) affected

控制台中没有其他消息生成,现在表数据中具有这4个值。 我删除了(1,1)以外的所有内容,因此可以在相同的游戏环境中进行测试

INSERT INTO users_partners (uid,pid) VALUES (1,1),(1,2),(1,3),(1,4) ON DUPLICATE KEY UPDATE uid=uid
...3 row(s) affected

REPLACE INTO users_partners (uid,pid) VALUES (1,1),(1,2),(1,3),(1,4)
...5 row(s) affected

所以你有它。 由于这都是在几乎没有数据且不在生产中的新表上执行的,因此执行时间是微观的且无关紧要的。 任何拥有真实数据的人都将非常乐意为您提供数据。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值