我目前遇到主键ID
设置为auto increment
的问题。它不断递增ON DUPLICATE KEY
。
例如:
ID | field1 | field2
1 | user | value
5 | secondUser | value
86 | thirdUser | value
从上面的描述中,您会注意到我在该表中有3个输入但由于每次更新时自动递增,因此第三个输入的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 ;
答案 0 :(得分:5)
您可以将innodb_autoinc_lock_mode
配置选项设置为"0"
以用于“传统”自动增量锁定模式,这样可以保证所有INSERT
语句都为AUTO_INCREMENT
分配连续值列。
也就是说,您不应该依赖应用程序中连续的自动增量ID。他们的目的是提供唯一标识符。
答案 1 :(得分:1)
下面使用innodb_autoinc_lock_mode
= 1(“连续”锁定模式)的默认设置很容易看到此行为。另请参阅标题为AUTO_INCREMENT Handling in InnoDB的精细手册页。对于“Tranditional”锁定模式,更改此值将降低并发性和性能,因为它使用表级别的AUTO-INC锁定。
也就是说,以下是默认设置= 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 |
+----+--------------------+---------+
Gap(跳过id = 2)是由于INNODB
引擎的一些操作和怪癖以及紧张抽搐之一造成的。在其默认的高性能并发模式下,它为发送给它的各种查询执行范围间隙分配。最好有理由改变这个设置,因为这样做会影响性能。 MySQL的后期版本会为您提供各种各样的东西,并且由于Hyper Focusing打印输出表中的空白(以及“我们为什么会有空白”的老板)而关闭。
如果在重复密钥更新(IODKU
)上插入,则假设有1个新行并为其分配一个插槽。记住,并发性和你的同行做同样的操作,可能是数百个并发。当IODKU变成Update
时,那么,对于你的连接和其他任何人,使用那个被遗弃且从未插入id = 2的行。
示例2:
Insert ... Select From
期间发生同样的事情,如我This Answer所见。在其中我故意使用MyISAM
由于报告计数,最小值,最大值,否则范围间隙怪癖将分配而不是全部填充。当答案涉及实际数字时,数字看起来很奇怪。因此,较旧的引擎(MyISAM
)可以很好地用于紧密的无间隙。请注意,在该答案中,我尝试快速安全地执行某项操作,并且事后可以使用INNODB
将表格转换为ALTER TABLE
。如果我在INNODB
开始做那个例子,就会有很多空白(在默认模式下)。 Insert ... Select From
会的原因在我使用INNODB
的答案中造成的差距是由于计数的不确定性,引擎选择安全的机制(不确定)范围分配。 INNODB
引擎自然地知道操作,知道必须创建AUTO_INCREMENT
id的安全池,并发(其他用户要考虑),并且差距蓬勃发展。这是事实。尝试使用INNODB
引擎的示例2,看看你为min,max和count提出了什么。 Max不等于数。
示例3和4:
有各种各样的情况导致Percona网站上记录INNODB
差距,因为他们偶然发现并记录下来。例如,由于在此1452 Error image中看到外键约束,它会在失败的插入期间发生。或此1062 Error image中的主键错误。
请记住,INNODB
差距是系统性能和安全引擎的副作用。为了更严格的id范围,是否真的想要关闭(性能,更高的用户满意度,更高的并发性,缺少表锁)?无论如何都有删除漏洞的范围。我建议不要使用我的实现,并且使用Performance的默认设置就好了。
答案 2 :(得分:0)
我目前遇到设置为主键
ID
的问题auto increment
。它不断递增ON DUPLICATE KEY
我们中的一个人必须误解这个问题,否则你就会歪曲它。 ON DUPLICATE KEY UPDATE
永远不会创建新行,因此无法递增。来自the docs:
如果指定ON DUPLICATE KEY UPDATE,则插入一行 会在UNIQUE索引或PRIMARY KEY,MySQL中导致重复值 执行旧行的更新。
现在可能会出现插入时发生自动增量并且找到没有重复键的情况。如果我认为这就是正在发生的事情,我的问题是:为什么这是一个问题?
如果您绝对想要控制主键的值,请更改表结构以删除auto-increment
标志,但将其保留为必需的非空字段。它会迫使你自己提供钥匙,但我敢打赌,这对你来说会更加令人头痛。
我真的很好奇:为什么你需要插入ID
值中的所有漏洞?
答案 3 :(得分:0)
我回答了here: 要解决自动递增问题,请在插入/复制重复更新部分之前使用以下代码,并一起执行所有操作:
SET @NEW_AI = (SELECT MAX(`the_id`)+1 FROM `table_blah`);
SET @ALTER_SQL = CONCAT('ALTER TABLE `table_blah` AUTO_INCREMENT =', @NEW_AI);
PREPARE NEWSQL FROM @ALTER_SQL;
EXECUTE NEWSQL;
一句话,它应该像下面这样:
SET @NEW_AI = (SELECT MAX(`the_id`)+1 FROM `table_blah`);
SET @ALTER_SQL = CONCAT('ALTER TABLE `table_blah` AUTO_INCREMENT =', @NEW_AI);
PREPARE NEWSQL FROM @ALTER_SQL;
EXECUTE NEWSQL;
INSERT INTO `table_blah` (`the_col`) VALUES("the_value")
ON DUPLICATE KEY UPDATE `the_col` = "the_value";
答案 4 :(得分:0)
您可以从以下位置更改查询
INSERT INTO table ( f1, f2 ) VALUES (:v1, :v2) ON DUPLICATE KEY UPDATE f1 = :v1, f2 = :v2
到
insert ignore into table select (select max(id)+1 from table), :v1, :v2 ;
这将尝试