防止InnoDB自动增加重复密钥

我目前有一个主键ID设置为auto increment 。 它不断递增ON DUPLICATE KEY

例如:

 ID | field1 | field2 1 | user | value 5 | secondUser | value 86 | thirdUser | value 

从上面的描述中,您会注意到在该表中有3个input,但是由于每次更新都会自动增加,所以第三个input的ID为86。

有没有办法避免这种情况?

以下是我的mySQL查询的样子:

 INSERT INTO table ( field1, field2 ) VALUES (:value1, :value2) ON DUPLICATE KEY UPDATE field1 = :value1, field2 = :value2 

这就是我的桌子的样子

 CREATE TABLE IF NOT EXISTS `table` ( `id` int(11) NOT NULL AUTO_INCREMENT, `field1` varchar(200) NOT NULL, `field2` varchar(255) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `field1` (`field1`), KEY `id` (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ; 

您可以将innodb_autoinc_lock_modeconfiguration选项设置为"0"作为“传统”自动增量locking模式,从而确保所有INSERT语句都将为AUTO_INCREMENT列分配连续值。

也就是说,您不应该依赖于应用程序中连续的自动递增ID。 他们的目的是提供唯一的标识符。

我目前有一个主键ID设置为auto increment 。 它不断递增ON DUPLICATE KEY

我们中的一个必须误解这个问题,否则你就是在歪曲事实。 ON DUPLICATE KEY UPDATE永远不会创build一个新行,所以它不能递增。 从文档 :

如果指定ON DUPLICATE KEY UPDATE,并且插入的行将导致UNIQUE索引或PRIMARY KEY中出现重复值,则MySQL会执行旧行的UPDATE。

现在可能是在插入时发生自动增量,并且没有find重复的键。 如果我认为这是发生了什么,我的问题是:为什么这是一个问题?

如果您绝对要控制主键的值,请更改您的表结构以删除auto-increment标志,但将其保留为必需的非空字段。 它会迫使你自己提供钥匙,但我敢打赌,这将成为你更大的头痛。

我真的很好奇:为什么你需要堵塞ID值的所有漏洞?

innodb_autoinc_lock_mode = 1(“连续”locking模式)的默认设置在下面很容易看到。 请参考在InnoDB中名为“ AUTO_INCREMENT Handling”的精细手册页。 对于“Tranditional”locking模式,更改此值将降低并发性和性能,设置为= 0,因为它使用表级AUTO-INClocking。

这就是说,下面是默认设置= 1。

我正要向你们展示四个例子:创造差距是多么的容易。

例1:

 create table x ( id int auto_increment primary key, someOtherUniqueKey varchar(50) not null, touched int not null, unique key(someOtherUniqueKey) ); insert x(touched,someOtherUniqueKey) values (1,'dog') on duplicate key update touched=touched+1; insert x(touched,someOtherUniqueKey) values (1,'dog') on duplicate key update touched=touched+1; insert x(touched,someOtherUniqueKey) values (1,'cat') on duplicate key update touched=touched+1; select * from x; +----+--------------------+---------+ | id | someOtherUniqueKey | touched | +----+--------------------+---------+ | 1 | dog | 2 | | 3 | cat | 1 | +----+--------------------+---------+ 

间隙(id = 2被跳过)是由于INNODB引擎的一些操作和怪癖和紧张的抽动之一。 在默认的高性能并发模式下,它为发送给它的各种查询执行范围间隙分配。 一个人最好有很好的理由来改变这个设置,因为这样做会影响性能。 MySQL的后续版本会提供给你,并且由于Hyper Focusing在打印输出表(和老板们说“我们为什么有差距”)中的空白而closures。

在插入复制密钥更新( IODKU )的情况下,它假设1个新行并为其分配一个时隙。 记住,并发性和你的同行做同样的操作,可能是几百个同时操作。 当IODKU变成一个Update时,那么对于你的连接和其他任何人来说,使用id = 2的被遗弃的,从不插入的行。

例2:

Insert ... Select From我的这个答案中看到相同的情况。 其中我故意使用MyISAM报告计数,最小值,最大值,否则范围缺口怪异将分配,而不是所有。 而这个数字看起来很奇怪,因为这个答案涉及到实际的数字。 所以旧的引擎( MyISAM )在没有间隙的情况下工作得很好。 请注意,在那个答案我试图做一些快速和安全的事情后,该表可以转换为INNODBALTER TABLE后事实。 如果我在INNODB做了这个例子,那么就会有很多差距(在默认模式下)。 Insert ... Select From的原因导致在那个答案我已经使用INNODB差距是由于计数的不确定性,引擎select安全(不确定)范围分配的机制。 INNODB引擎自然而然地知道操作,知道必须创build一个AUTO_INCREMENT ID的安全池,具有并发性(其他用户去思考),并且缺口在发展。 这是事实。 试用INNODB引擎的例子2,看看你想出最小,最大和计数。 最大不会等于数。

实施例3和4:

在Percona网站上有各种情况会导致INNODB差距logging在他们绊倒更多和logging它们。 例如,由于在此1452错误图像中看到的外键约束,在插入失败期间发生。 或在此1062错误图像中的主键错误。

请记住, INNODB间隙是系统性能和安全引擎的副作用。 是否真的想要closures(性能,更高的用户满意度,更高的并发性,缺乏表锁),为了更严格的id范围? 无论如何,删除漏洞的范围。 我会build议不为我的实现,性能的默认就好了。