百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 编程字典 > 正文

关于MySQL中insert ignore,insert on duplicate和replace into,你可能没想过区别

toyiye 2024-06-21 12:14 7 浏览 0 评论

这是学习笔记的第 2187篇文章

读完需要

分钟

速读仅需5分钟

在数据流转中或者日常的数据操作中,势必会有数据写入的过程,如果把一些数据写入一张数据库表中,如果写入量有100万,而重复的数据有90万,那么如何让这10%的数据能够更高更高效的写入。

在MySQL方向提供了Insert ignore into,insert into on duplicate,replace into这几种写入的方式,看起来好像都差不多,但是实际上在一些场景下的差异还比较大,如果使用不当,恰恰是性能的瓶颈。

整体上我分为两个大的部分,会分别测试这三种数据写入场景。

第一部分基于id,name的数据列,其中id为主键,自增

第二部分基于id,xid,name的数据列,其中id为主键,自增,xid为唯一性索引

至于为什么要这么分,我们可以先看结果再做讨论。

基于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 AUTO_INCREMENT,

`name` varchar(30) DEFAULT ,

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 AUTO_INCREMENT,

`name` varchar(30) DEFAULT ,

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 AUTO_INCREMENT,

`name` varchar(30) DEFAULT ,

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 AUTO_INCREMENT,

`name` varchar(30) DEFAULT ,

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

基于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 AUTO_INCREMENT,

`xid` int(11) DEFAULT ,

`name` varchar(30) DEFAULT ,

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 AUTO_INCREMENT,

`xid` int(11) DEFAULT ,

`name` varchar(30) DEFAULT ,

PRIMARY KEY (`id`),

UNIQUE KEY `xid` (`xid`)

) ENGINE=InnoDB AUTO_INCREMENT=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对于重复数据依然会消耗自增列值,实现相对更加灵活。

相关推荐

kong api gateway 初体验(konga github)

kongapigateway初体验(firstsight?)。Kong是一个可扩展的开源API层(也称为API网关或API中间件)。Kong运行在任何RESTfulAPI的前面,并通过插件...

在Ubuntu下开启IP转发的方法(ubuntu20 ip)

IP地址分为公有ip地址和私有ip地址,PublicAddress是由INIC(internetnetworkinformationcenter)负责的,这些IP地址分配给了注册并向INIC提...

基于 Kubernetes 的 Serverless PaaS 稳定性建设万字总结

作者:许成铭(竞霄)数字经济的今天,云计算俨然已经作为基础设施融入到人们的日常生活中,稳定性作为云产品的基本要求,研发人员的技术底线,其不仅仅是文档里承诺的几个九的SLA数字,更是与客户切身利益乃...

跟老韩学Ubuntu Linux系列-sysctl 帮助文档

sysctl一般用于基于内核级别的系统调优,man帮助手册如下。...

如何在 Linux/Unix/Windows 中发现隐藏的进程和端口

unhide是一个小巧的网络取证工具,能够发现那些借助rootkit、LKM及其它技术隐藏的进程和TCP/UDP端口。这个工具在Linux、UNIX类、MS-Windows等操作系统下都...

跟老韩学Ubuntu Server 2204-Linux性能管理-uptime指令帮助手册

uptime指令是每个从事Linux系统工作的相关同学必知必会的指令之一,如下是uptime指令的帮助手册。UPTIME(1)...

Openwrt+Rclone+emby+KODI搭建完美家庭影音服务器

特别声明:本篇内容参考了波仔分享,在此表示感谢!上一篇《Openwrt+emby+KODI搭建家庭影音服务器》只适用影音下载到本地的情形,不能播放云盘中的影音,内容较少,缺少了趣味性,也不直观。...

Linux Shell脚本经典案例(linux shell脚本例子)

编写Shell过程中注意事项:开头加解释器:#!/bin/bash语法缩进,使用四个空格;多加注释说明。命名建议规则:变量名大写、局部变量小写,函数名小写,名字体现出实际作用。默认变量是全局的,在函数...

解决 Linux 性能瓶颈的黄金 60 秒

如果你的Linux服务器突然负载暴增,告警短信快发爆你的手机,如何在最短时间内找出Linux性能问题所在?来看Netflix性能工程团队的这篇博文,看它们通过十条命令在一分钟内对机器性能问题进行诊断。...

跟老韩学Ubuntu Server 2204-Linux性能管理-vmstat指令帮助手册

vmstat可查看ubuntlinux的综合性能,是每个从事Linux人员必知必会、需掌握的核心指令之一。vmstat指令帮助手册如下。VMSTAT(8)...

Python 可视化工具包(python常见的可视化工具)

喜欢用Python做项目的小伙伴不免会遇到这种情况:做图表时,用哪种好看又实用的可视化工具包呢?本文将介绍一些常用的Python可视化包,包括这些包的优缺点以及分别适用于什么样的场景。这篇文章...

Python的GPU编程实例——近邻表计算

目录技术背景...

python算法体验-3.python实现欧式距离的三种方式

欧式距离也称欧几里得距离,是最常见的距离度量,衡量的是多维空间中两个点之间的绝对距离。欧式距离源自N维欧氏空间中两点...

python实现Lasso回归分析(特征筛选、建模预测)

实现功能:...

python语言检测模块langid、langdetect使用

本文首发地址:https://blog.csdn.net/Together_CZ/article/details/86678423欢迎关注我的博客【Together_CZ】,我是沂水寒城!之前使用数据...

取消回复欢迎 发表评论:

请填写验证码