[大阪/横滨/德岛] 寻找基础设施/服务器端工程师!

[大阪/横滨/德岛] 寻找基础设施/服务器端工程师!

【超过500家企业部署】AWS搭建、运维、监控服务

【超过500家企业部署】AWS搭建、运维、监控服务

【CentOS的后继者】AlmaLinux OS服务器搭建/迁移服务

【CentOS的后继者】AlmaLinux OS服务器搭建/迁移服务

[仅适用于 WordPress] 云服务器“Web Speed”

[仅适用于 WordPress] 云服务器“Web Speed”

[便宜]网站安全自动诊断“快速扫描仪”

[便宜]网站安全自动诊断“快速扫描仪”

[预约系统开发] EDISONE定制开发服务

[预约系统开发] EDISONE定制开发服务

[注册100个URL 0日元] 网站监控服务“Appmill”

[注册100个URL 0日元] 网站监控服务“Appmill”

【兼容200多个国家】全球eSIM“超越SIM”

【兼容200多个国家】全球eSIM“超越SIM”

[如果您在中国旅行、出差或驻扎]中国SIM服务“Choco SIM”

[如果您在中国旅行、出差或驻扎]中国SIM服务“Choco SIM”

【全球专属服务】Beyond北美及中国MSP

【全球专属服务】Beyond北美及中国MSP

[YouTube]超越官方频道“美由丸频道”

[YouTube]超越官方频道“美由丸频道”

这个查询可以吗? 如果您不知道的话,您将丢失 REPLACE 子句的行为

你好。我是Mandai,负责Wild 开发团队。
这次,我想了解 REPLACE 子句的详细行为,我(也许)会随意使用它。

 

您如何更新数据?

我们公司使用MySQL作为主要的RDBMS进行系统开发。
通常,当更新具有唯一约束的表时,

  • 选择,检查重复项,然后插入、更新或分支
  • 尝试 INSERT 和 Duplicate 的疯狂更新,捕获异常并将其发送到 UPDATE 处理

您可能被迫在以下选项之间进行选择,但实际上(尽管这不是什么大问题)还存在使用 REPLACE 子句的更新处理。

对于这个REPLACE子句,如果你认为它只是简单地替换(=REPLACE),那么执行它时,可能会出现数据不一致的情况,并可能出现意想不到的情况。

让我们用一个简单的例子来看看它的行为。

让我们看看实际行动

首先,创建一个如下所示的表。

mysql> CREATE TABLE `users` (`id` INT UNSIGNED NOT NULL PRIMARY KEY AUTO_INCRMENT, `name` VARCHAR(16) NOT NULL UNIQUE, `level` INT UNSIGNED NOT NULL DEFAULT 1); 查询正常,0 行受影响(0.02 秒); ) mysql> DESC `用户`; +--------+--------------------+------+----+- --------+----------------+ | 类型 | 额外 | ------------------+------+----+---------+--------- - ------+ | int(10) | NULL | varchar(16) | 空 | | 1 | +--------+-----+-----+-----+----- ---------+ 3 行一组(0.00 秒)

名称字段设置为唯一键。
接下来,让我们插入一些简单的虚拟数据。

这次,generateddata.com生成虚拟数据

我想气氛会是这样的。

mysql> 插入 `users` (`name`,`level`) 值 ("Pamela",8),("Dexter",4),("Ava",1),("Kelly",8),( "Leila",2),("Quin",8),("Salvador",8),("Orli",2),("Ignacia",9),("Brennan",8); 查询OK,受影响的 10 行(0.00 秒)记录:10 重复项:0 警告:0 mysql> SELECT * FROM `users`; +----+----------+--------+ | 姓名 | +----+------+ | 8 | 1 | 4 | 2 | 8 | 伊格纳西亚 | +----+----------+--------+ 10 行一组(0.00 秒)

现在,我想插入具有重复名称的记录。

mysql> INSERT INTO `users` (`name`,`level`) VALUES ("Pamela",1); 错误 1062 (23000): 重复条目 'Pamela' 为键 'name' mysql> SELECT * FROM `users`; +----+----------+-----+ | 名称 | +----+----------+- ------+ | 2 | 4 | 5 | 7 | 8 | 9 | 布伦南 | -+ 10 行一组(0.00 秒)

由于重复而发生错误。
这正如预期的那样。

通常,您可以在此处使用 UPDATE 子句来更新记录。

mysql> UPDATE `users` SET `level`=10 WHERE `name` = "Pamela"; 查询正常,1 行受影响(0.00 秒)匹配的行:1 已更改:1 警告:0 mysql> select * from users; ---+----------+-----+ | 名称 | +----+----------+--- ----+ | 10 | 4 | 凯利 | 6 8 | 8 | 9 | 8 | +----+----------+已设置(0.00 秒)

接下来,让我们使用 REPLACE 子句来更新记录。

mysql> REPLACE INTO `users` (`name`,`level`) VALUES ("Pamela",1); 查询正常,2 行受影响(0.00 秒) mysql> SELECT * FROM `users`; ----------+--------+ | 名称 | +----+----------+----- + | 4 | 4 | 雷拉 | 8 | | 9 | 布伦南 | 1 | +----+----------+秒)

此时你是否意识到发生了可怕的事情?
是的,由于某种原因,name =“Pamela”的记录的主键已更改!
我想仔细看看这个事实,它就像稻川润二的鬼故事一样可怕。

REPLACE 子句不仅仅是替换

这个事实从前面提到的实验中已经很清楚了,但是为什么会出现这种情况呢?
顺便说一句,id 11缺失的原因是因为执行了INSERT子句,而这不是这个鬼故事的内容。

简单来说,出现这种情况的原因是

DELETE 之后的 REPLACE 子句“插入具有相同数据的记录”

这是因为它像这样移动。
太可怕了。
自行更改主键是很可怕的。
如果你认为这是一个方便的查询,自动判断是INSERT还是UPDATE,并且你反复使用它
,那么你只是没有踩到地雷,在你意识到之前,你可能已经陷入了一片汪洋大海地雷。

然而,出现这种现象的原因是

  • 有一个自动递增的主键
  • 有些字段也是唯一键。
  • 当唯一键重复时

仅限于。
当我这样写时,有些人似乎说这是因为我添加了代理键,但我认为正确的答案是他们在知道 REPLACE 子句的行为后没有实现它。

有一种类似的语法,称为“INSERT ... ON DUPLICATE KEY UPDATE 语法”,但

用于基于语句的复制或具有复合主(唯一)键的表是不安全的,
此外,许多框架 O/R 映射器不作为标准支持(因为它们是 MySQL 的方言,而不是标准 SQL),因此如果您使用它们,您将不会从 O/R 映射器中受益。
不过,据说 ON DUPLICATE KEY UPDATE 语法的处理速度比 SELECT → INSERT (UPDATE) 快得多,因此
如果您使用的是 MySQL 系统并且数据更新处理需要很长时间,尝试使用它可能会是一个不错的选择尝试使用它的想法。

MySQL 5.6系列日文文档
MySQL 5.7系列文档(英文)
(内容与英文版5.7系列文档大致相同)

另外,暂时INSERT会导致自增不必要的计数,
可能会导致主键耗尽的悲剧。
如果你想确定的话,我认为执行 SELECT → INSERT (UPDATE) 是个好主意。

嗯, generatedata.com确实很有用。

如果您觉得这篇文章有帮助,请点赞!
5
加载中...
5 票,平均:1.00 / 15
21,610
X Facebook 哈特纳书签 口袋
[2025.6.30 Amazon Linux 2 支持结束] Amazon Linux 服务器迁移解决方案

[2025.6.30 Amazon Linux 2 支持结束] Amazon Linux 服务器迁移解决方案

[大阪/横滨] 积极招募基础设施工程师和服务器端工程师!

[大阪/横滨] 积极招募基础设施工程师和服务器端工程师!

写这篇文章的人

关于作者

万代洋一

我的主要工作是为社交游戏开发 Web API,但我也很幸运能够做很多其他工作,包括营销。
此外,我在 Beyond 中的肖像权被视为 CC0。