[转] MySQL "replace into" 的坑 (5.5 ROW格式)
MySQL 对 SQL 有很多扩展,有些用起来很方便,但有一些被误用之后会有性能问题,还会有一些意料之外的副作用,比如 REPLACE INTO。
比如有这样一张表:
1 |
|
auto 表有一个自增的 id 字段作为主键,字段 k 有 UNIQUE KEY 做唯一性约束。写入几条记录之后会是这样:
1 |
|
在 slave 节点上是和 master 一致的:
1 |
|
可以看到,写入三条记录之后,auto 表的 AUTO_INCREMENT 增长为 4,也就是说下一条不手工为 id 指定值的记录,id 字段的值会是 4。
接下来使用 REPLACE INTO 来写入一条记录:
1 |
|
可以看到 MySQL 说 “2 rows affected”,可是明明是只写一条记录,为什么呢?这是因为 MySQL 在执行 REPLACE INTO auto (k) VALUES (1) 时首先尝试 INSERT INTO auto (k) VALUES (1),但由于已经存在一条 k=1 的记录,发生了 duplicate key error,于是 MySQL 会先删除已有的那条 k=1 即 id=1 的记录,然后重新写入一条新的记录。
这时候 slave 上出现了诡异的问题:
1 |
|
可以知道,当前表内数据 id 字段的最大值是 4,AUTO_INCREMENT 应该为 5,但在 slave 上 AUTO_INCREMENT 却并未更新,这会有什么问题呢?把这个 slave 提升为 master 之后,由于 AUTO_INCREMENT 比实际的 next id 还要小,写入新记录时就会发生 duplicate key error,每次冲突之后 AUTO_INCREMENT += 1,直到增长为 max(id) + 1 之后才能恢复正常:
1 |
|
没有预料到 MySQL 在数据冲突时实际上是删掉了旧记录,再写入新记录,这是使用 REPLACE INTO 时最大的一个误区,拿之前的例子来说,执行完 REPLACE INTO auto (k, v) VALUES (1, ‘1-1’) 之后,由于新写入记录时并未给 extra 字段指定值,原记录 extra 字段的值就「丢失」了,而通常这并非是业务上所预期的,更常见的需求实际上是,当存在 k=1 的记录时,就把 v 字段的值更新为 ‘1-1’,其他未指定的字段则保持原状,而满足这一需求的 MySQL 方言是 INSERT INTO auto (k, v) VALUES (1, ‘1-1’) ON DUPLICATE KEY UPDATE v=VALUES(v);
鉴于此,很多使用 REPLACE INTO 的场景,实际上需要的是 INSERT INTO … ON DUPLICATE KEY UPDATE,在正确理解 REPLACE INTO 行为和副作用的前提下,谨慎使用 REPLACE INTO。
原文地址:
https://blog.xupeng.me/2013/10/11/mysql-replace-into-trap/
[转] MySQL "replace into" 的坑 (5.5 ROW格式)的更多相关文章
- MySQL "replace into" 的坑
MySQL 对 SQL 有很多扩展,有些用起来很方便,但有一些被误用之后会有性能问题,还会有一些意料之外的副作用,比如 REPLACE INTO. 比如有这样一张表: CREATE TABLE `au ...
- MySQL "replace into" 的坑以及insert相关操作
下面我们主要说一下在插入时候的几种情况: 1:insert ignore 2:replace into 3:ON DUPLICATE KEY UPDATE 关于insert ignore: 关于rep ...
- MySQL replace into 使用详解 及 注意事项
REPLACE的运行与INSERT很相似.只有一点例外,假如表中的一个旧记录与一个用于PRIMARY KEY或一个UNIQUE索引的新记录具有相同的值,则在新记录被插入之前,旧记录被删除.注意:除非表 ...
- MySQL REPLACE INTO 的使用
前段时间写游戏合服工具时出现过一个问题,源DB和目标DB角色表中主键全部都不相同,从源DB取出玩家数据再使用 replace into 写入目标DB中,结果总有几条数据插入时会导致目标DB中原有的角色 ...
- MySQL replace函数替换字符串语句的用法(mysql字符串替换)
MySQL replace函数我们经常用到,下面就为您详细介绍MySQL replace函数的用法,希望对您学习MySQL replace函数方面能有所启迪. 最近在研究CMS,在数据转换的时候需要用 ...
- 被mysql中的wait_timeout坑了
今天被mysql里的wait_timeout坑了 网上能搜到很多关于mysql中的wait_timeout相关的文章,但是大多数只是说明了他的作用,而且都说这个参数要配合那个inter ...
- MySQL replace into 说明(insert into 增强版)
MySQL replace into 说明(insert into 增强版) 在插入数据到一个表时,通常是这种情况:1. 先推断数据是否存在: 2. 假设不存在,则插入:3.假设存在,则更新. 在 S ...
- 【踩坑记录】记一次MySQL主从复制延迟的坑
最近开发中遇到的一个MySQL主从延迟的坑,记录并总结,避免再次犯同样的错误. 情景 一个活动信息需要审批,审批之后才能生效.因为之后活动要编辑,编辑后也可能触发审批,审批中展示的是编辑前的活动内容, ...
- Ubuntu 16.04 安装Mysql 5.7 踩坑小记
title:Ubuntu 16.04 安装Mysql 5.7 踩坑小记 date: 2018.02.03 安装mysql sudo apt-get install mysql-server mysql ...
随机推荐
- 【洛谷3345_BZOJ3924】[ZJOI2015]幻想乡战略游戏(点分树)
大概有整整一个月没更博客了 -- 4 月为省选爆肝了一个月,最后压线进 B 队,也算给 NOIP2018 翻车到 316 分压线省一这个折磨了五个月的 debuff 画上了一个不算太差的句号.结果省选 ...
- C#时间相关方法
当前电脑的时间: DateTime.Now//当前时间 DateTime.Now.Date//当前日期的 0:00:00 DateTime.Now.ToLongDateString();//显示日期 ...
- Apache Calcite项目简介
文章导读: 什么是Calcite? Calcite的主要功能? 如何快速使用Calcite? 什么是Calcite Apache Calcite是一个动态数据管理框架,它具备很多典型数据库管理系统的功 ...
- iOS检测耳机插入拔出
首先,需要导入两个框架 然后,注册通知检测耳机的插入与拔出操作 [[NSNotificationCenter defaultCenter] addObserver:self selector:@sel ...
- UIPickerView 多级联动
UIPickerView的多级联动问题有些地方需要注意,其实多级联动并不难...楼主因为项目需要又没法使用网上的第三方,所以最近写了一个省市区多级联动,还是手写代码好!! 为了演示效果,我会多定义几个 ...
- 【C++】Item18. Make interfaces easy to use correctly and hard to use incorrectly
接口容易被正确使用,不易被误用 c++简单工厂模式时,初级实现为ITest* CreateTestOld(), 然后用户负责释放返回的对象.如果忘记释放就会造成memory leak,所以在设计工厂接 ...
- JavaScript(十二)事件
Dom事件 1.DOM0级事件 on事件 只能 监听冒泡阶段 切只能绑定一个事件 dom.onclick = function(){}; 2.Dom2级事件 可以绑定多次事件 可以通过设置fla ...
- BPI-MI1刷Andorid的启动卡之后上网的步骤(以太网&&WIFI)
BPI-MI1刷Andorid的启动卡之后上网的步骤(以太网&&WIFI) 2017/9/19 16:57 01刷Android的默认启动界面.png 02打开英文模式下的设置Sett ...
- 网络编程基础_3.APC队列
APC队列 #include <stdio.h> #include <windows.h> // 保存 IO 操作的结果 CHAR Buffer1[] = { }; CHAR ...
- 搭建linux环境:如何在vmware安装linux虚拟机??
本来不想再整一遍的,奈何分布式压测呀,呀呀呀呀呀呀 1.安装linux虚机 (1)在桌面上双击VMware Workstation图标后启动虚拟机,鼠标单击文件,选择新的虚拟机: (2)单击“next ...