ON DUPLICATE KEY + AUTO INCREMENT问题mysql

new*_*bie 24 mysql

我有这样的表结构

在此输入图像描述

当我向表中插入行时,我正在使用此查询:

INSERT INTO table_blah ( material_item, ... hidden ) VALUES ( data, ... data ) ON DUPLICATE KEY UPDATE id = id, material_item = data, ... hidden = data;

当我第一次插入数据而不触发ON DUPLICATE KEYid增量罚款:

在此输入图像描述

但是当ON DUPLICATE KEY触发器和我插入新行时,id看起来很奇怪:

在此输入图像描述

auto increment即使触发,我怎样才能保持正确的增量ON DUPLICATE KEY

Gor*_*off 40

记录此行为:

如果指定ON DUPLICATE KEY UPDATE,并且插入的行将导致UNIQUE索引或PRIMARY KEY中出现重复值,则MySQL将执行旧行的UPDATE.例如,如果列a声明为UNIQUE并包含值1,则以下两个语句具有类似的效果:

    INSERT INTO table (a,b,c) VALUES (1,2,3)   ON DUPLICATE KEY UPDATE c=c+1;

    UPDATE table SET c=c+1 WHERE a=1;
Run Code Online (Sandbox Code Playgroud)

(对于一个自动增量列的InnoDB表,效果并不相同.对于自动增量列,INSERT语句会增加自动增量值,但UPDATE不会.)

这是一个简单的解释.MySQL首先尝试进行插入.这是id自动递增的时候.一旦增加,它就会停留.然后检测到副本并进行更新.但是这个价值被遗漏了.

你不应该依赖于auto_increment没有差距.如果这是一项要求,则更新和插入的开销要大得多.实质上,您需要锁定整个表,并重新编号需要重新编号的所有内容,通常使用触发器.更好的解决方案是计算输出的增量值.

  • 这是mysql的愚蠢问题.好的,我没有传达它没有间隙,但是今天我只有大约500000条记录经常更新时达到了16000000+行(MEDIUMINT)的命中限制.问题是我有另外一个超过250Gb大小的表链接到这个 - 并且将它更新为INT(并且当它完全不需要时松散的存储空间)需要数天. (15认同)
  • 我不明白这个设计背后的原因.虽然我不介意这些差距,但我认为没有理由因为ID从未存在而发生自动增量,因此它只会创建大量垃圾ID. (6认同)
  • +1。说得好。感谢您提供实际文档。;-) (3认同)
  • 我使用`ON DUPLICATE KEY UPDATE`定期更新多个记录。我不在乎差距,但是我担心会碰到最大列值。每次批量更新后,定期使用“ ALTER TABLE table_name AUTO_INCREMENT = 1”(将auto_increment重置为最后一行id + 1)会是一个不好的做法吗? (2认同)

小智 9

这个问题是一个相当老的问题,但我回答它也许可以帮助某人,解决自动递增问题,在插入/重复更新部分之前使用以下代码并一起执行它们:

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; 
Run Code Online (Sandbox Code Playgroud)

放在一起并在一份声明中应该如下所示:

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";
Run Code Online (Sandbox Code Playgroud)

  • 所有像“不要担心差距”这样的答案都是垃圾,这应该被接受。我的 ID 数字用完了,我使用上面的代码进行 INSERT,一次添加了许多值,效果非常好。谢谢 ;) (4认同)