【问题标题】:ON DUPLICATE KEY adding rowsON DUPLICATE KEY 添加行
【发布时间】:2018-01-17 21:49:09
【问题描述】:

好的,所以我有下表:

CREATE TABLE `Tags` (
  `tag_id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `tag` varchar(100) DEFAULT NULL,
  PRIMARY KEY (`tag_id`),
  UNIQUE KEY `tag` (`tag`),
  KEY `tag_id` (`tag_id`)
) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8;
SET FOREIGN_KEY_CHECKS=1;

当我运行以下查询时,它似乎在增加主键,即使它找到重复项(即使它没有添加重复项)。

INSERT INTO Tags (tag) VALUES ('book'),('cats'),('dogs') ON DUPLICATE KEY UPDATE tag = tag

你得到...

tag_id | tag
==============================
1      | book
2      | robots
3      | doodles
5      | cats
6      | dogs
==============================

如何防止这种情况发生?

【问题讨论】:

  • 没有什么可以阻止的。 auto_increment 的号码已用完。它们永远不会被重复使用。这就是它的工作原理,如果它看起来“愚蠢” - 它不是。如果你试图“解决”这个问题,你实际上会造成伤害。查询似乎也不合适,看起来好像您在INSERT IGNORE之后。

标签: mysql insert duplicates unique


【解决方案1】:

您无法真正阻止这种情况,您不必担心。自动递增的 id 中的间隙几乎从来都不是问题。

发生的事情是 MySQL 正在尝试插入行。为了插入行,它必须构造它——因此自动递增的列是递增的。当已经找到该行时,插入失败,但自动增量已经递增。

如果您想最小化问题,您可以尝试在尝试插入之前 找到重复项:

INSERT INTO Tags (tag) 
    SELECT t.tag
    FROM (SELECT 'book' as tag UNION ALL
          SELECT 'cats' as tag UNION ALL
          SELECT 'dogs' as tag
         ) t
    WHERE NOT EXISTS (SELECT 1 FROM Tags t2 WHERE t2.tag = t.tag)
    ON DUPLICATE KEY UPDATE tag = VALUES(tag);

这不是 100% 的修复 - 子查询可能有重复,或者其他进程可能会在运行时更新表。但是,它通常会避免插入不应该插入的记录。

【讨论】:

  • 感谢您的解释。这是有道理的。我将不得不修改我的程序,因此除非必要,否则它不会进行这些添加,否则我最终可能会得到一个非常大的主键表。回到绘图板:)
  • @Hugo - 使您的pk bigint 为您提供2^64 - 1 的范围。即使你每秒浪费几千把钥匙,你也应该可以用几千年 :)
【解决方案2】:

查看innodb_autoinc_lock_mode。当前设置为什么?设置innodb_autoinc_lock_mode = 0 可能会给你想要的,但它默认为1

除此之外,您的密钥 tag_id (tag_id) 是多余的,因为它已经是您的主密钥。

【讨论】:

  • 感谢您的提示!会修改!
猜你喜欢
  • 2014-03-10
  • 1970-01-01
  • 1970-01-01
  • 2017-12-09
  • 2015-12-10
  • 2011-05-16
  • 1970-01-01
  • 2018-12-01
  • 2017-04-24
相关资源
最近更新 更多