在我的MySQL表中,我创建了一个ID列,我希望自动增加它以使其成为主键。
我创建了我的桌子:
CREATE TABLE `test` (
`id` INT( 11 ) NOT NULL AUTO_INCREMENT PRIMARY KEY ,
`name` VARCHAR( 50 ) NOT NULL ,
`date_modified` DATETIME NOT NULL ,
UNIQUE (
`name`
)
) TYPE = INNODB;
然后插入我的记录:
INSERT INTO `test` ( `id` , `name` , `date_modified` )
VALUES (
NULL , 'TIM', '2011-11-16 12:36:30'
), (
NULL , 'FRED', '2011-11-16 12:36:30'
);
我期待上面的ID分别是1和2(分别)。到目前为止,这是事实。 但是,当我做这样的事情时:
insert into test (name) values ('FRED')
on duplicate key update date_modified=now();
然后插入一条新记录,我希望它是3,但是现在我显示的是4;跳过场地3点。
通常这不会是一个问题,但我使用的数百万条记录每天都有数以千计的更新...而且我真的不想因为我的问题而不得不考虑耗尽ID跳过大量的数字..
Anyclue为何会发生这种情况?
MySQL版本:5.1.44
谢谢
答案 0 :(得分:4)
我的猜测是INSERT本身会启动生成下一个ID号的代码。当检测到重复键并且执行ON DUPLICATE KEY UPDATE时,将放弃ID号。 (没有SQL dbms保证自动序列没有间隙,AFAIK。)
通常,您应该尽量避免使用ON DUPLICATE KEY UPDATE 具有多个唯一索引的表的子句。
该页面也说
如果表包含AUTO_INCREMENT列并且INSERT ... ON DUPLICATE KEY UPDATE插入或更新一行,LAST_INSERT_ID() function返回AUTO_INCREMENT值。
远远没有描述我在上面猜到的内部行为。
不能在这里测试;将稍后再试。
答案 1 :(得分:3)
是否可以将您的密钥更改为unsigned bigint - 18,446,744,073,709,551,615是很多记录 - 从而延迟了ID的耗尽
在mysql手册http://dev.mysql.com/doc/refman/5.1/en/example-auto-increment.html
中找到了这个Use a large enough integer data type for the AUTO_INCREMENT column to hold the
maximum sequence value you will need. When the column reaches the upper limit of
the data type, the next attempt to generate a sequence number fails. For example,
if you use TINYINT, the maximum permissible sequence number is 127.
For TINYINT UNSIGNED, the maximum is 255.
更多阅读http://dev.mysql.com/doc/refman/5.6/en/information-functions.html#function_last-insert-id可以推断,事务表的插入是回滚,所以手册说“LAST_INSERT_ID()没有恢复到事务之前的那个”
使用表生成ID然后使用LAST_INSERT_ID()插入主表作为PK的可能解决方案怎么样;
从手册:
Create a table to hold the sequence counter and initialize it:
mysql> CREATE TABLE sequence (id INT NOT NULL);
mysql> INSERT INTO sequence VALUES (0);
Use the table to generate sequence numbers like this:
mysql> UPDATE sequence SET id=LAST_INSERT_ID(id+1);
mysql> SELECT LAST_INSERT_ID();
The UPDATE statement increments the sequence counter and causes the next call to
LAST_INSERT_ID() to return the updated value. The SELECT statement retrieves that
value. The mysql_insert_id() C API function can also be used to get the value.
See Section 20.9.3.37, “mysql_insert_id()”.
答案 2 :(得分:0)
这是一个真正的错误,你可以在这里看到:http://bugs.mysql.com/bug.php?id=26316 但是,显然,他们将其修复为 5.1.47 ,并将其声明为INNODB插件问题。 一个重复但同样的问题,你也可以在这里看到:http://bugs.mysql.com/bug.php?id=53791引用了这个答案中提到的第一页。