关于MySQL中insert ignore,insert on duplicate和replace into,你可能没想过区别
这是学习笔记的第 2187 篇文章
读完需要
10
分钟
速读仅需5分钟
在数据流转中或者日常的数据操作中,势必会有数据写入的过程,如果把一些数据写入一张数据库表中,如果写入量有100万,而重复的数据有90万,那么如何让这10%的数据能够更高更高效的写入。
在MySQL方向提供了Insert ignore into,insert into on duplicate,replace into这几种写入的方式,看起来好像都差不多,但是实际上在一些场景下的差异还比较大,如果使用不当,恰恰是性能的瓶颈。
整体上我分为两个大的部分,会分别测试这三种数据写入场景。
第一部分基于id,name的数据列,其中id为主键,自增
第二部分基于id,xid,name的数据列,其中id为主键,自增,xid为唯一性索引
至于为什么要这么分,我们可以先看结果再做讨论。
1
基于id,name的数据列,其中id为主键,自增
为了三种测试场景的基准对等,数据初始化会按照如下的三种方式来进行。
数据初始化
create table test_data(id int primary key auto_increment,name varchar(30)) engine=innodb; | |
insert into test_data values(1,'aa'),(2,'bb'),(3,'cc'); | |
show create table test_data\G Table: test_data Create Table: CREATE TABLE `test_data` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(30) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8 |
insert ignore
insert ignore into test_data values(1,'aa'); Query OK, 0 rows affected, 1 warning (0.00 sec) >>show warnings; +---------+------+---------------------------------------+ | Level | Code | Message | +---------+------+---------------------------------------+ | Warning | 1062 | Duplicate entry '1' for key 'PRIMARY' | +---------+------+---------------------------------------+ 1 row in set (0.00 sec) |
show create table test_data\G Table: test_data Create Table: CREATE TABLE `test_data` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(30) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8 |
insert ignore into test_data values(1,'aaa'); Query OK, 0 rows affected, 1 warning (0.01 sec) >>show warnings; +---------+------+---------------------------------------+ | Level | Code | Message | +---------+------+---------------------------------------+ | Warning | 1062 | Duplicate entry '1' for key 'PRIMARY' | +---------+------+---------------------------------------+ 1 row in set (0.00 sec) |
insert ignore into test_data values(4,'cc'); Query OK, 1 row affected (0.01 sec) |
select * from test_data; +----+------+ | id | name | +----+------+ | 1 | aa | | 2 | bb | | 3 | cc | | 4 | cc | +----+------+ 4 rows in set (0.00 sec) |
replace into场景
>>replace into test_data values(1,'aa'); Query OK, 1 row affected (0.01 sec) |
show create table test_data\G Table: test_data Create Table: CREATE TABLE `test_data` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(30) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8 |
replace into test_data values(1,'aaa'); Query OK, 2 rows affected (0.00 sec) |
replace into test_data values(4,'cc'); Query OK, 1 row affected (0.00 sec) |
select *from test_data; +----+------+ | id | name | +----+------+ | 1 | aaa | | 2 | bb | | 3 | cc | | 4 | cc | +----+------+ 4 rows in set (0.00 sec) |
insert into on duplicate场景
insert into test_data values(1,'aa') on duplicate key update id=id; Query OK, 0 rows affected (0.00 sec) insert into test_data values(1,'aa') on duplicate key update id=id, name=name; Query OK, 0 rows affected (0.00 sec) |
show create table test_data\G Table: test_data Create Table: CREATE TABLE `test_data` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(30) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8 |
insert into test_data values(1,'aaa') on duplicate key update id=id; Query OK, 0 rows affected (0.00 sec) insert into test_data values(1,'aaa') on duplicate key update id=id,name=name; Query OK, 0 rows affected (0.00 sec) |
insert into test_data values(4,'cc') on duplicate key update id=id; Query OK, 1 row affected (0.01 sec) insert into test_data values(4,'ccc') on duplicate key update id=id, name=name; Query OK, 0 rows affected (0.00 sec) |
select * from test_data; +----+------+ | id | name | +----+------+ | 1 | aa | | 2 | bb | | 3 | cc | | 4 | cc | +----+------+ 4 rows in set (0.00 sec) |
小结:这三种场景的结果从自增列的处理方式来看是完全对等的,但是对于重复数据的处理方式还是存在差异。
相比而言,replace into和insert into on duplicate存在本质的区别,replace into是覆盖写,即删除原来的,写入新的。不光是主键列,其他列也会保持一致
insert into on duplicate则可以根据自己的需求来定制重复数据的处理策略,不会主动改变数据。
insert ignore into 在这种场景下最为通用,而且对于数据的侵入性最小。
所以如果要保证源端的数据基于主键完全一致,不管非主键列的数据是否一致,都需要完全覆盖,选择replace into是一种好的方法。
否则采用insert into on duplcate或者insert ignore into
2
基于id,xid,name的数据列,其中id为主键,自增,xid为唯一性索引
为了三种测试场景的基准对等,数据初始化会按照如下的三种方式来进行。
数据初始化
create table test_data(id int primary key auto_increment,xid int unique key,name varchar(30)) engine=innodb; | ||
insert into test_data(xid,name) values(1,'aa'),(2,'bb'),(3,'cc'); Query OK, 3 rows affected (0.01 sec) Records: 3 Duplicates: 0 Warnings: 0 |
||
select *from test_data; +----+------+------+ | id | xid | name | +----+------+------+ | 1 | 1 | aa | | 2 | 2 | bb | | 3 | 3 | cc | +----+------+------+ 3 rows in set (0.00 sec) |
insert ignore into
insert ignore into test_data(xid,name) values(1,'aa'); Query OK, 0 rows affected, 1 warning |
CREATE TABLE `test_data` ( `id` int(11) NOT NULL AUTO_INCREMENT, `xid` int(11) DEFAULT NULL, `name` varchar(30) DEFAULT NULL, PRIMARY KEY (`id`), UNIQUE KEY `xid` (`xid`) ) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8 |
insert ignore into test_data(xid,name) values(1,'aaa'); Query OK, 0 rows affected, 1 warning (0.01 sec) mysql--root@localhost:test 18:58:13>>show warnings; |
insert ignore into test_data(xid,name) values(4,'dd'); Query OK, 1 row affected (0.00 sec) |
Create Table: CREATE TABLE `test_data` ( `id` int(11) NOT NULL AUTO_INCREMENT, `xid` int(11) DEFAULT NULL, `name` varchar(30) DEFAULT NULL, PRIMARY KEY (`id`), UNIQUE KEY `xid` (`xid`) ) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8 |
>select * from test_data; +----+------+------+ | id | xid | name | +----+------+------+ | 1 | 1 | aa | | 2 | 2 | bb | | 3 | 3 | cc | | 6 | 4 | dd | +----+------+------+ 4 rows in set (0.00 sec) |
replace into
replace into test_data(xid,name) values(1,'aa'); Query OK, 2 rows affected (0.00 sec) |
+----+------+------+ | id | xid | name | +----+------+------+ | 2 | 2 | bb | | 3 | 3 | cc | | 4 | 1 | aa | +----+------+------+ 3 rows in set (0.00 sec) |
replace into test_data(xid,name) values(1,'aaa'); Query OK, 2 rows affected (0.01 sec) |
select *from test_data; +----+------+------+ | id | xid | name | +----+------+------+ | 2 | 2 | bb | | 3 | 3 | cc | | 5 | 1 | aaa | +----+------+------+ |
replace into test_data(xid,name) values(4,'cc'); Query OK, 1 row affected (0.00 sec) |
select *from test_data; +----+------+------+ | id | xid | name | +----+------+------+ | 2 | 2 | bb | | 3 | 3 | cc | | 5 | 1 | aaa | | 6 | 4 | dd | +----+------+------+ 4 rows in set (0.00 sec) |
insert into on duplicate
insert into test_data(xid,name) values(1,'aa') on duplicate key update xid=xid; Query OK, 0 rows affected (0.00 sec) insert into test_data(xid,name) values(1,'aa') on duplicate key update xid=xid, name=name; Query OK, 0 rows affected (0.01 sec) |
+----+------+------+ | id | xid | name | +----+------+------+ | 1 | 1 | aa | | 2 | 2 | bb | | 3 | 3 | cc | +----+------+------+ 3 rows in set (0.00 sec) |
insert into test_data(xid,name) values(1,'aaa') on duplicate key update xid=xid; Query OK, 0 rows affected (0.01 sec) insert into test_data(xid,name) values(1,'aaa') on duplicate key update xid=xid,name=name; |
insert into test_data(xid,name) values(4,'cc') on duplicate key update xid=xid; Query OK, 1 row affected (0.01 sec) insert into test_data(xid,name) values(4,'ccc') on duplicate key update xid=xid, name=name; Query OK, 0 rows affected (0.00 sec) |
select * from test_data; +----+------+------+ | id | xid | name | +----+------+------+ | 1 | 1 | aa | | 2 | 2 | bb | | 3 | 3 | cc | | 8 | 4 | cc | +----+------+------+ 4 rows in set (0.00 sec) |
小结:在这个场景里面,可以看到三种场景的变化真是很大,而且区别也很明显。
insert ignore into如果不指定自增列,尽管没有写入数据,但是自增列依然会自增
replace into如果不指定自增列,会看到数据重新写入的效果已经非常明显,而且自增列始终会自动维护。
insert into on duplicate对于重复数据依然会消耗自增列值,实现相对更加灵活。
QQ群号:763628645
QQ群二维码如下, 添加请注明:姓名+地区+职位,否则不予通过
3
关于MySQL中insert ignore,insert on duplicate和replace into,你可能没想过区别相关推荐
- MYSQL常用语法命令,MySQL中delete,drop和alter分别是用来删除什么的?有什么区别?删除了以后可以恢复吗?
1.Alter.Delete.Drop相关语法 a.Alter 删除,添加或重新定义列 删除列:alter table tablename drop columnname 增加列:alter tabl ...
- Mysql中update select更新数据,insert ignore into
在mysql中一般更新我们都是通过 update set指定的值,但是有些时候,我们数据库中存在一些记录,这时候我们希望用已有数据库中的记录来进行更新,这时候我们可以通过mysql的update se ...
- MySQL中关于insert语句速度的优化
1.分析 插入一行分下面几个动作,括号后面是其大约比例额 Connecting(3) Sendint query to server(2) Parsing query(2) Inserting row ...
- MySQL 纯insert_MySQL使用INSERT插入多条记录
MySQL使用INSERT插入多条记录,应该如何操作呢?下面就为您详细介绍MySQL使用INSERT插入多条记录的实现方法,供您参考. 看到这个标题也许大家会问,这有什么好说的,调用多次INSERT语 ...
- 转载:MySQL数据库INSERT、UPDATE、DELETE以及REPLACE语句的用法详解
转自:http://www.jb51.net/article/39199.htm 本篇文章是对MySQL数据库INSERT.UPDATE.DELETE以及REPLACE语句的用法进行了详细的分析介绍, ...
- 在MySql中,这四种方法可以避免重复插入数据!
前言 MySql 在存在主键冲突或唯一键冲突的情况下,根据插入方式,一般有以下四种插入方式避免错误. insert ignore. replace into insert on duplicate k ...
- 实践 | 在MySql中,这四种方法可以避免重复插入数据!
前言 MySql 在存在主键冲突或唯一键冲突的情况下,根据插入方式,一般有以下四种插入方式避免错误. insert ignore. replace into insert on duplicate k ...
- 数据库mysql中delimiter的作用和用法
mysql中解释器以分号作为结束标记. 但有时候虽然不想终止,但是又想要执行某一段呢? delimiter|| CREATE TRIGGER changeAvgAge AFTER INSERT ON ...
- oracle触发器比较,Oracle使用触发器和mysql中使用触发器的比较
一.触发器 1.触发器在数据库里以独立的对象存储, 2.触发器不需要调用,它由一个事件来触发运行 3.触发器不能接收参数 --触发器的应用 举个例子:校内网.开心网.facebook,当你发一个日志, ...
- mysql中的BIT_LENGTH和LENGTH以及CHAR_LENGTH的区别
mysql中获取字符的长度的常见函数有以上三种,他们的区别在于衡量长度的单位是不同的. 目录 背景描述 mysql中长度函数描述 使用案例 背景描述 ASCII码 因为计算机是美国人发明和最早使用的, ...
最新文章
- JavaScript深度学习
- 计算机考试不用输入扩展名吗,本周末的 计算机等级考试,如果不想考0分,一定要花2分钟看完...
- 【bzoj4832】[Lydsy1704月赛]抵制克苏恩 期望dp
- c++求解自行车慢速比赛问题_一元一次方程应用专题,十大题型(包括数轴上动点问题)...
- PyTorch深度学习实践02
- Usermod 命令详解
- Python3 字典
- 运行jar中某个类的main方法
- 目录启动CXF启动报告LinkageError异常以及Java的endorsed机制
- 【 2019中国大学生程序设计竞赛(CCPC) - 网络选拔赛】1002.array【主席树】
- GBase 8c 备份控制函数(四)
- 计算机八进制 算法视频,八进制转二进制计算器
- 清华大学--代理服务器
- python中while和for的运行顺序_详解python while 函数及while和for的区别
- android 怎么改变字体颜色,安卓系统字体颜色修改教程
- 天下武功,无坚不破,唯快不破
- 强化学习9——贝尔曼方程
- Android常用RGB值以及中英文名称
- 变量相关性分析(决策变量和目标函数之间的关系-决策变量可加可分离性)
- mybatis 配置多数据源 java,SpringBoot+MyBatisPlus配置多数据源读写分离