为什么INSERT IGNORE会增加auto_increment主键?

时间:2011-04-13 20:45:48

标签: mysql

我编写了一个访问MySQL innodb数据库的java程序。

每当INSERT IGNORE语句遇到重复条目时,Auto Increment主键就会递增。

这种行为是预期的吗?我认为IGNORE不应该发生这种情况。这意味着IGNORE实际上会产生额外的开销来写入新的主键值。

表格如下:

CREATE TABLE `tablename` (
  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
  `rowname` varchar(50) NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `rowname` (`rowname`)
) ENGINE=InnoDB  DEFAULT CHARSET=latin1;

谢谢!

4 个答案:

答案 0 :(得分:31)

这是自MySQL 5.1.22以来的默认行为。

您可以将配置变量innodb_autoinc_lock_mode设置为0(a.k.a“传统”锁定模式)如果您想避免自动增量列中的间隙。但是,它可能会导致性能下降,因为此模式具有在INSERT完成之前保持表锁定的效果。

来自InnoDB AUTO_INCREMENT Lock Modes上的文档:

  

innodb_autoinc_lock_mode = 0 (“传统”锁定模式)

     

传统的锁定模式提供了与之相同的行为   在innodb_autoinc_lock_mode配置参数之前   在MySQL 5.1中引入。提供传统的锁定模式选项   用于向后兼容性,性能测试和解决方案   “混合模式插入”的问题,由于可能存在差异   语义。

     

在这种锁定模式下,所有“INSERT-like”语句都会获得一个特殊的声明   表级AUTO-INC锁定,用于插入AUTO_INCREMENT的表   列。此锁定通常持有到语句的末尾(不是   到交易结束时)确保自动增加值   按给定的可预测和可重复的顺序分配   INSERT语句的序列,并确保自动递增   任何给定语句分配的值都是连续的。

答案 1 :(得分:10)

我相信这是InnoDB中的可配置设置。请参阅:AUTO_INCREMENT Handling in InnoDB

你想和

一起去
innodb_autoinc_lock_mode = 0

答案 2 :(得分:1)

我认为这种行为是合理的。不应依赖自动增量来给出没有间隙的序列。

例如,回滚事务仍然使用ID:

 INSERT INTO t (normalcol, uniquecol) VALUES 
   ('hello','uni1'),
   ('hello','uni2'),
   ('hello','uni1');

显然会生成唯一的密钥违规,并且不会在数据库中插入任何行(假设此处为事务引擎)。但是,它可能会消耗多达3个auto-inc值而不插入任何内容。

答案 3 :(得分:-2)

不确定是否预期,但我建议切换到:

INSERT ... ON DUPLICATE KEY UPDATE