ON DUPLICATE KEY + AUTO INCREMENT问题mysql

时间:2014-05-07 11:46:49

标签: mysql

我有这样的表结构

enter image description here

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

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

当我第一次插入数据而没有触发ON DUPLICATE KEY时,id增量很好:

enter image description here

但是当ON DUPLICATE KEY触发并且我插入新行时,ID对我来说很奇怪:

enter image description here

即使auto increment触发ON DUPLICATE KEY,我如何保持{{1}}正确递增?

9 个答案:

答案 0 :(得分:35)

记录了此行为:

  

如果指定ON DUPLICATE KEY UPDATE,则插入一行   会在UNIQUE索引或PRIMARY KEY,MySQL中导致重复值   执行旧行的更新。例如,如果列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;
     

(效果不一样   一个InnoDB表,其中a是一个自动增量列。与   自动递增列,INSERT语句增加   自动递增值,但UPDATE不会。)

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

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

答案 1 :(得分:1)

我有同样的挫败感,也有解决方案。

首先让我谈谈“开销”。当我第一次编写数据库更新代码时,它执行了许多单独的查询,因此花费了5个小时。一旦我进行了“ ON DUPLICATE KEY UPDATE”,我将其降低到大约50秒。惊人!无论如何,我解决它的方式意味着我必须执行2个查询,所以我将其扩展到2分钟而不是1分钟,我认为这是一个合理的成本。

首先,我对包含更新和插入数据的数据进行了标准的sql查询,但是我包含了“ IGNORE”,因此这只会绕过更新而仅插入新内容。 “将IGNORE插入mytablename(stuff,stuff2)VALUES中”-无需重复更新键。这意味着将放入所有新记录。这些新记录仍不会破坏auto_increment。

接下来,我执行了该sql语句的“ ON DUPLICATE KEY UPDATE”版本,现在这会破坏auto_increment值,但是我们输入的所有更新和插入内容都是完美的auto_incrememnt值。只是我们添加的下一条新记录是错误的...

因此,最后您只需通过此sql修补混乱: “ ALTER TABLE mytablename AUTO_INCREMENT =”。 ($ TableCount + 1);

请记住实际上将$ TableCount设置为表计数,然后我们加1,这样就可以在下一条记录写入时使用了。

这便宜又脏,但是我喜欢。确保不要同时使用另一个函数等向数据库写入数据,因为这可能会导致错误。我认为有一种方法可以锁定桌子?但我不需要这种情况。

答案 2 :(得分:1)

我经常通过创建一个临时表来处理这个问题,在临时表中记录记录是否是新的,仅对非新行执行 UPDATE,并对新行执行 INSERT。这是一个完整的示例:

## THE SETUP

# This is the table we're trying to insert into
DROP TABLE IF EXISTS items;
CREATE TABLE items (
  id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
  name VARCHAR(100) UNIQUE,
  price INT
);

# Put a few rows into the table
INSERT INTO items (name, price) VALUES
  ("Bike", 200),
  ("Basketball", 10),
  ("Fishing rod", 25)
;

## THE INSERT/UPDATE

# Create a temporary table to help with the update
DROP TEMPORARY TABLE IF EXISTS itemUpdates;
CREATE TEMPORARY TABLE itemUpdates (
  name VARCHAR(100) UNIQUE,
  price INT,
  isNew BOOLEAN DEFAULT(true)
);

# Change the price of the Bike and Basketball and add a new Tent item
INSERT INTO itemUpdates (name, price) VALUES
  ("Bike", 150),
  ("Basketball", 8),
  ("Tent", 100)
;

# For items that already exist, set isNew false
UPDATE itemUpdates
JOIN items
ON items.name = itemUpdates.name
SET isNew = false;

# UPDATE the already-existing items
UPDATE items
JOIN itemUpdates
ON items.name = itemUpdates.name
SET items.price = itemUpdates.price
WHERE itemUpdates.isNew = false;

# INSERT the new items
INSERT INTO items (name, price)
SELECT name, price
FROM itemUpdates
WHERE itemUpdates.isNew = true;

# Check the results
SELECT * FROM items;
# Results:
# ID | Name        | Price
# 1  | Bike        | 150
# 2  | Basketball  | 8
# 3  | Fishing rod | 25
# 4  | Tent        | 100
        

INSERT IGNORE INTO 方法更简单,但它忽略了任何 错误,这不是我想要的。我同意这是 MySQL 的一种奇怪行为,但这是我们必须处理的。

答案 3 :(得分:0)

这个问题是一个相当老的问题,但我回答可能对某人有帮助,要解决自动递增问题,请在插入/复制重复更新部分之前使用以下代码并将其全部执行:

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; 

一句话,它应该像下面这样:

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";

答案 4 :(得分:0)

我只是想补充一下,因为我试图找到解决问题的方法。 我无法停止重复的警告,发现这是因为我将其设置为TINYINT,它仅允许127个条目,更改为SMALL / MED / BIGINT则允许更多

答案 5 :(得分:0)

我不认为这是 MySQL 5.6 的问题。见this example

答案 6 :(得分:0)

重复密钥更新 id=LAST_INSERT_ID(id)

答案 7 :(得分:0)

将数据库引擎从 InnoDB 更改为 MyIsam 将解决您的问题。

答案 8 :(得分:-1)

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

是删除ID = ID,因为它会自动添加PRIMARY KEY = PRIMARY KEY ...