防止自动增量跳过重复键更新

时间:2017-10-03 09:36:08

标签: mysql indexing insert

我有一张表

(ID INT auto_incrment primary key, 
tag VARCHAR unique)

我想在一个插入多个标签。像这样:

INSERT INTO tags (tag) VALUES ("java"), ("php"), ("phyton");

如果我执行此操作,并且“java”已经在表中,我收到错误。它不添加“php”和“phyton”。

如果我这样做:

INSERT INTO tags (tag) VALUES ("java"), ("php"), ("phyton") 
    ON DUPLICATE KEY UPDATE tag = VALUES(tag)

它会在没有错误的情况下添加,但会在ID字段中跳过2个值。

示例:我使用ID = 1的Java并运行查询。然后PHP将是3和Phyton 4.有没有办法执行此查询而不跳过ID?

我不希望他们之间有大的空间。我也试过INSERT IGNORE

谢谢!

2 个答案:

答案 0 :(得分:0)

参见" SQL#1"在http://mysql.rjweb.org/doc.php/staging_table#normalization。它更复杂,但避免燃烧' IDS。它具有在另一个表中需要标签的潜在缺点。该链接的摘录:

# This should not be in the main transaction, and it should be
#    done with autocommit = ON
# In fact, it could lead to strange errors if this were part
#    of the main transaction and it ROLLBACKed.
INSERT IGNORE INTO Hosts (host_name)
    SELECT DISTINCT s.host_name
        FROM Staging AS s
        LEFT JOIN Hosts AS n  ON n.host_name = s.host_name
        WHERE n.host_id IS NULL;

通过将其隔离为自己的事务,我们可以快速完成它,从而最大限度地减少阻塞。通过说IGNORE,我们并不关心其他线程是否同时“关注”。插入相同的host_names。 (如果您没有其他帖子执行此类INSERTs,则可以抛出IGNORE

(然后继续讨论IODKU。)

答案 1 :(得分:0)

INNODB 引擎其主要特点是支持 ACID 类型的事务。

我指出的通常不是“问题”,而是引擎会在知道它是否重复之前“保留”ID。 这是一个解决方案,但它取决于您的表,如果我们谈论的是一个非常大的表,您应该先做一些测试,因为 AUTO_INCREMENT 函数可以帮助您遵循 id 的顺序。

我会给你一些例子

INSERT INTO tags (java,php,python) VALUES ("val1"), ("val2"), ("val3") 
ON DUPLICATE KEY UPDATE java = VALUES(java), id = LAST_INSERT_ID(id); 

SELECT LAST_INSERT_ID();

ALTER TABLE tags AUTO_INCREMENT = 1;

注意:我给你添加了 LAST_INSERT_ID() 因为每次你插入或更新它总是给你一个插入或保留的 id。 每次调用 INSERT INTO 时,都必须遵循 AUTO_INCREMNT。