MySQL Auto-Inc Bug?

时间:2011-11-16 18:42:58

标签: mysql primary-key auto-increment

在我的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

谢谢

3 个答案:

答案 0 :(得分:4)

我的猜测是INSERT本身会启动生成下一个ID号的代码。当检测到重复键并且执行ON DUPLICATE KEY UPDATE时,将放弃ID号。 (没有SQL dbms保证自动序列没有间隙,AFAIK。)

MySQL docs

  

通常,您应该尽量避免使用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引用了这个答案中提到的第一页。