这是学习笔记的第 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;
+---------+------+-----------------------------------+
| Level   | Code | Message                           |
+---------+------+-----------------------------------+
| Warning | 1062 | Duplicate entry '1' for key 'xid' |
+---------+------+-----------------------------------+

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;
Query OK, 0 rows affected (0.00 sec)

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,你可能没想过区别相关推荐

  1. MYSQL常用语法命令,MySQL中delete,drop和alter分别是用来删除什么的?有什么区别?删除了以后可以恢复吗?

    1.Alter.Delete.Drop相关语法 a.Alter 删除,添加或重新定义列 删除列:alter table tablename drop columnname 增加列:alter tabl ...

  2. Mysql中update select更新数据,insert ignore into

    在mysql中一般更新我们都是通过 update set指定的值,但是有些时候,我们数据库中存在一些记录,这时候我们希望用已有数据库中的记录来进行更新,这时候我们可以通过mysql的update se ...

  3. MySQL中关于insert语句速度的优化

    1.分析 插入一行分下面几个动作,括号后面是其大约比例额 Connecting(3) Sendint query to server(2) Parsing query(2) Inserting row ...

  4. MySQL 纯insert_MySQL使用INSERT插入多条记录

    MySQL使用INSERT插入多条记录,应该如何操作呢?下面就为您详细介绍MySQL使用INSERT插入多条记录的实现方法,供您参考. 看到这个标题也许大家会问,这有什么好说的,调用多次INSERT语 ...

  5. 转载:MySQL数据库INSERT、UPDATE、DELETE以及REPLACE语句的用法详解

    转自:http://www.jb51.net/article/39199.htm 本篇文章是对MySQL数据库INSERT.UPDATE.DELETE以及REPLACE语句的用法进行了详细的分析介绍, ...

  6. 在MySql中,这四种方法可以避免重复插入数据!

    前言 MySql 在存在主键冲突或唯一键冲突的情况下,根据插入方式,一般有以下四种插入方式避免错误. insert ignore. replace into insert on duplicate k ...

  7. 实践 | 在MySql中,这四种方法可以避免重复插入数据!

    前言 MySql 在存在主键冲突或唯一键冲突的情况下,根据插入方式,一般有以下四种插入方式避免错误. insert ignore. replace into insert on duplicate k ...

  8. 数据库mysql中delimiter的作用和用法

    mysql中解释器以分号作为结束标记. 但有时候虽然不想终止,但是又想要执行某一段呢? delimiter|| CREATE TRIGGER changeAvgAge AFTER INSERT ON ...

  9. oracle触发器比较,Oracle使用触发器和mysql中使用触发器的比较

    一.触发器 1.触发器在数据库里以独立的对象存储, 2.触发器不需要调用,它由一个事件来触发运行 3.触发器不能接收参数 --触发器的应用 举个例子:校内网.开心网.facebook,当你发一个日志, ...

  10. mysql中的BIT_LENGTH和LENGTH以及CHAR_LENGTH的区别

    mysql中获取字符的长度的常见函数有以上三种,他们的区别在于衡量长度的单位是不同的. 目录 背景描述 mysql中长度函数描述 使用案例 背景描述 ASCII码 因为计算机是美国人发明和最早使用的, ...

最新文章

  1. JavaScript深度学习
  2. 计算机考试不用输入扩展名吗,本周末的 计算机等级考试,如果不想考0分,一定要花2分钟看完...
  3. 【bzoj4832】[Lydsy1704月赛]抵制克苏恩 期望dp
  4. c++求解自行车慢速比赛问题_一元一次方程应用专题,十大题型(包括数轴上动点问题)...
  5. PyTorch深度学习实践02
  6. Usermod 命令详解
  7. Python3 字典
  8. 运行jar中某个类的main方法
  9. 目录启动CXF启动报告LinkageError异常以及Java的endorsed机制
  10. 【 2019中国大学生程序设计竞赛(CCPC) - 网络选拔赛】1002.array【主席树】
  11. GBase 8c 备份控制函数(四)
  12. 计算机八进制 算法视频,八进制转二进制计算器
  13. 清华大学--代理服务器
  14. python中while和for的运行顺序_详解python while 函数及while和for的区别
  15. android 怎么改变字体颜色,安卓系统字体颜色修改教程
  16. 天下武功,无坚不破,唯快不破
  17. 强化学习9——贝尔曼方程
  18. Android常用RGB值以及中英文名称
  19. 变量相关性分析(决策变量和目标函数之间的关系-决策变量可加可分离性)
  20. mybatis 配置多数据源 java,SpringBoot+MyBatisPlus配置多数据源读写分离

热门文章

  1. API平台都有的Appid、Appkey、Appsecret分别是什么意思?
  2. windows多网卡叠加网速
  3. Flutter(十七) 实现国际化
  4. 滴滴AI负责人叶杰平离职,CTO张博暂时接管
  5. man fgetc fgets getc getchar ungetc
  6. MPC-HC 播放器设置
  7. 【职场心灵鸡汤】以多年来拿最佳的心路历程来复盘【如何成为优秀的5%】
  8. pytorch读取tif文件方法
  9. Win11dns解析状态异常怎么处理?Win11dns解析失败解决方法
  10. 进制转换C语言实现(十进制转换为任意进制)