防止 MySQL 重复插入自动递增
使用 MySQL 5.1.49,我正在尝试实现一个标记系统 我遇到的问题是一个包含两列的表:id(autoincrement)
,tag(unique varchar)
(InnoDB)
当使用查询时, INSERT IGNORE INTO tablename SET tag="whatever"
,即使插入被忽略,自动递增id
值也会增加。
通常这不会是一个问题,但我预计会有很多可能的尝试为这个特定的表插入重复项,这意味着我的新行的 id 字段的下一个值将跳跃太多。
例如,我最终会得到一个包含 3 行但 id
不正确的表。
1 | test
8 | testtext
678 | testtextt
另外,如果我不执行 INSERT IGNORE
操作,而只执行常规 INSERT INTO
并处理错误,自动增量字段仍然增加,因此下一个真正的插入仍然是错误的自动增量。
如果尝试插入重复行,是否有办法停止自动增量?
据我了解,对于 MySQL 4.1,这个值不会增加,但我想做的最后一件事是最终要么提前执行大量 SELECT 语句来检查标签是否存在,或者更糟,降级我的MySQL版本。
Using MySQL 5.1.49, I'm trying to implement a tagging system
the problem I have is with a table with two columns: id(autoincrement)
, tag(unique varchar)
(InnoDB)
When using query, INSERT IGNORE INTO tablename SET tag="whatever"
, the auto increment id
value increases even if the insert was ignored.
Normally this wouldn't be a problem, but I expect a lot of possible attempts to insert duplicates for this particular table which means that my next value for id
field of a new row will be jumping way too much.
For example I'll end up with a table with say 3 rows but bad id
's
1 | test
8 | testtext
678 | testtextt
Also, if I don't do INSERT IGNORE
and just do regular INSERT INTO
and handle the error, the auto increment field still increases so the next true insert is still a wrong auto increment.
Is there a way to stop auto increment if there's an INSERT
duplicate row attempt?
As I understand for MySQL 4.1, this value wouldn't increment, but last thing I want to do is end up either doing a lot of SELECT
statements in advance to check if the tags exist, or worse yet, downgrade my MySQL version.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(9)
您可以将 INSERT 修改为如下所示:
其中
$tag
是您要添加的标签(正确引用或作为占位符)(如果它尚不存在)。如果标签已经存在,这种方法甚至不会触发 INSERT(以及随后的自动增量浪费)。您可能会想出比这更好的 SQL,但上面的方法应该可以解决问题。如果你的表被正确索引,那么用于存在性检查的额外 SELECT 将会很快,并且数据库无论如何都必须执行该检查。
但这种方法不适用于第一个标签。您可以使用您认为最终会被使用的标签来播种标签表,或者您可以对空表进行单独检查。
You could modify your INSERT to be something like this:
Where
$tag
is the tag (properly quoted or as a placeholder of course) that you want to add if it isn't already there. This approach won't even trigger an INSERT (and the subsequent autoincrement wastage) if the tag is already there. You could probably come up with nicer SQL than that but the above should do the trick.If your table is properly indexed then the extra SELECT for the existence check will be fast and the database is going to have to perform that check anyway.
This approach won't work for the first tag though. You could seed your tag table with a tag that you think will always end up being used or you could do a separate check for an empty table.
我刚刚找到了这个宝石...
http:// www.timrosenblatt.com/blog/2008/03/21/insert-where-not-exists/
如果affectedRows = 1则插入;否则,如果affectedRows = 0,则存在重复项。
I just found this gem...
http://www.timrosenblatt.com/blog/2008/03/21/insert-where-not-exists/
If affectedRows = 1 then it inserted; otherwise if affectedRows = 0 there was a duplicate.
v 5.5 的 MySQL 文档说:
Ref: http:// dev.mysql.com/doc/refman/5.5/en/information-functions.html#function_last-insert-id
从版本 5.1 开始,InnoDB 具有可配置的自动增量锁定。另请参阅http://dev.mysql。 com/doc/refman/5.1/en/innodb-auto-increment-handling.html#innodb-auto-inc...
解决方法:使用选项 innodb_autoinc_lock_mode=0 (传统)。
The MySQL documentation for v 5.5 says:
Ref: http://dev.mysql.com/doc/refman/5.5/en/information-functions.html#function_last-insert-id
Since version 5.1 InnoDB has configurable Auto-Increment Locking. See also http://dev.mysql.com/doc/refman/5.1/en/innodb-auto-increment-handling.html#innodb-auto-inc...
Workaround: use option innodb_autoinc_lock_mode=0 (traditional).
我发现 mu 太短的答案很有帮助,但有限制,因为它不会在空表上进行插入。我发现一个简单的修改就达到了目的:
用“假”表
(select 1)替换from子句中的表
(select 1)作为
允许该部分返回允许插入发生的记录。我正在运行 mysql 5.5.37。谢谢你带我去那里的大部分路......I found mu is too short's answer helpful, but limiting because it doesn't do inserts on an empty table. I found a simple modification did the trick:
Replacing the table in the from clause with a "fake" table
(select 1) as a
allowed that part to return a record which allowed the insert to take place. I'm running mysql 5.5.37. Thanks mu for getting me most of the way there ....接受的答案很有用,但是我在使用它时遇到了一个问题,基本上如果您的表没有条目,它将无法工作,因为选择正在使用给定的表,所以我想出了以下内容,即使表是空白的,也只需要在2处插入表,在1处插入变量,就不会出错。
希望你觉得它有用
The accepted answer was useful, however I ran into a problem while using it that basically if your table had no entries it would not work as the select was using the given table, so instead I came up with the following, which will insert even if the table is blank, it also only needs you to insert the table in 2 places and the inserting variables in 1 place, less to get wrong.
Hope you find it useful
您始终可以添加
ON DUPLICATE KEY UPDATE
来自@ravi 的评论
You can always add
ON DUPLICATE KEY UPDATE
Read here (not exactly, but solves your problem it seems).From the comments, by @ravi
我遇到了同样的问题,但不想使用 innodb_autoinc_lock_mode = 0 因为感觉就像我正在用榴弹炮杀死一只苍蝇。
为了解决这个问题,我最终使用了临时表。
然后我插入了以下值:
之后,您只需执行另一次插入,但使用“not in”来忽略重复项。
我还没有测试过它的性能,但它可以完成工作并且易于阅读。当然,这很重要,因为我正在处理不断更新的数据,所以我不能忽视这些差距。
I had the same problem but didn't want to use innodb_autoinc_lock_mode = 0 since it felt like I was killing a fly with a howitzer.
To resolve this problem I ended up using a temporary table.
Then I inserted the values with:
After that you simply do another insert but use "not in" to ignore duplicates.
I haven't tested this for performance, but it does the job and is easy to read. Granted this was only important because I was working with data that was constantly being updated so I couldn't ignore the gaps.
修改了mu的答案太短,(只需删除一行)
由于我是新手,我无法在他的回答下发表评论。只需将其发布到此处,
下面的查询适用于第一个标签
modified the answer from mu is too short, (simply remove one line)
as i am newbie and i cannot make comment below his answer. Just post it here
the query below works for the first tag
我只是在插入/更新查询之后添加了一条额外的语句:
更改表
表名
AUTO_INCRMENT = 1然后他自动选取最高的prim key id加1。
I just put an extra statement after the insert/update query:
ALTER TABLE
table_name
AUTO_INCREMENT = 1And then he automatically picks up the highest prim key id plus 1.