【问题标题】:MySQL Auto-Inc Bug?MySQL Auto-Inc 错误?
【发布时间】:2011-12-30 17:04:19
【问题描述】:

在我的 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,但是现在显示的 ID 为 4;跳过 3 的地方。

通常这不是问题,但我使用的记录数以百万计,每天都有数以千计的更新......而且我什至不想仅仅因为我是跳过一大堆数字..

知道为什么会这样吗?

MySQL 版本:5.1.44

谢谢

【问题讨论】:

    标签: mysql primary-key auto-increment


    【解决方案1】:

    是否可以将您的密钥更改为 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()”.
    

    【讨论】:

    • 他的主要问题是对于每个插入,一个键丢失,但你的观点很有意义。 auto_increment 的字段确实需要很大,否则会失败。
    • 是的,它可以是 unsigned 和 bigint,我都有,但是对于这个例子,我使用了一个 int。我预计每天有 10-20k 更新,如果其中一半在以后跳过新插入的行的数字,我只是担心我能达到那个数字..
    • 我认为 Catcall 是正确的。它在尝试之前保留下一个 ID,因为它还不知道它是否会插入或更新。
    • @Frederico - 如果每天丢失 1,000,000 个更新的数字 - 仍然需要大约 12,500,000 年才能溢出:-)
    【解决方案2】:

    你在这里看到的确实是一个错误:http://bugs.mysql.com/bug.php?id=26316 但是,显然,他们在 5.1.47 上修复了它,并被声明为 INNODB 插件问题。 重复但同样的问题,您也可以在这里看到:http://bugs.mysql.com/bug.php?id=53791 引用了此答案中提到的第一页。

    【讨论】:

    • 我刚刚在5.5.15版本转载
    • 我不清楚这些错误报告与 OP 的问题有什么关系。报告的错误与触发器和重复键有关; OP 不使用触发器,并且 id 编号被丢弃,而不是重复。
    • 隐式触发器检查重复键和修改日期,不是吗?还是我弄错了?
    【解决方案3】:

    我的猜测是 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() 函数返回 AUTO_INCREMENT 值。

    这远远不能描述我在上面猜到的内部行为。

    这里不能测试;稍后再试。

    【讨论】:

      猜你喜欢
      • 2014-12-02
      • 1970-01-01
      • 1970-01-01
      • 2015-01-02
      • 1970-01-01
      • 2011-09-11
      • 2013-06-13
      • 2012-06-23
      相关资源
      最近更新 更多