MySQL INSERT .... ON DUPLICATE UPDATE - 在自动增量中添加一个

M. *_* CA 13 php mysql innodb

我通过简单的点击计数器跟踪访问我的所有http_user_agents.下面在数据库中插入http_user_agent,此字段为Case Insensitive且为Unique.因此,当我们尝试插入它并找到DUPLICATE KEY时,它会向hits字段添加1.

问题是我的自动增量字段仍然增加,即使我们没有插入字段.我怎么能阻止这个?

$sql = "INSERT INTO `db_agency_cloud`.`tblRefHttpUsersAgent` SET `http_users_agent` = :UsersAgent, `created_ts` = NOW() ON DUPLICATE KEY UPDATE `hits` = `hits` + 1";
Run Code Online (Sandbox Code Playgroud)

这是表结构:

CREATE TABLE `tblRefHttpUsersAgent`
(
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`http_users_agent` varchar(255) NOT NULL,
`hits` int(20) unsigned NOT NULL DEFAULT '1',
`created_ts` datetime NOT NULL,
`activity_ts` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
UNIQUE KEY `http_users_agent` (`http_users_agent`)
)
ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1;
Run Code Online (Sandbox Code Playgroud)

Joh*_*ess 19

INSERT ... ON DUPLICATE KEY UPDATE被描述为InnoDB AUTO_INCREMENT处理的"混合模式插入" .混合模式插入基本上是已知最大所需AUTO_INCREMENT值的数量,但实际需要的数量不是.

默认情况下会专门处理混合模式插入,如MySQL文档中所述:

...对于"混合模式插入"... InnoDB将分配比要插入的行数更多的自动增量值.但是,自动分配的所有值都是连续生成(因此高于)最近执行的先前语句生成的自动增量值."超额"号码丢失了.

如果您使用InnoDB,您的替代方案是:

  1. 避免INSERT ... ON DUPLICATE KEY UPDATE.
  2. 对于"传统"自动增量锁定模式,将innodb_autoinc_lock_mode参数设置0为,这可以保证所有INSERT语句都为AUTO_INCREMENT列分配连续值.但是,这是通过在语句期间锁定来实现的,因此与此设置相关的性能损失.
  3. (推荐)忽略AUTO_INCREMENT列中的间隙.

注意:AUTO_INCREMENT在MyISAM下处理完全不同,MyISAM没有表现出这种行为.


Dan*_*man 5

存储引擎必须AUTO_INCREMENT在插入行之前递增值.它不知道插入是否会在那时失败.它不能简单地回滚增量,因为可能同时在其他连接上发生其他插入.这是正常行为,而不是您应该(或可以)改变的行为.其目的AUTO_INCREMENT是提供唯一标识符,而不是不间断的数字序列.

  • +1:很有趣!好吧,我明白为什么会发生这种情况(感谢您的回答);不过,这确实看起来很不幸。它一点也不直观,我什至认为它是一个 **bug**(无论是在 SQL 标准中,还是在 MySQL 中)......即使它总是被解析为“WONTFIX”。 (2认同)