MySQL实战中,Insert语句的使用心得总结

  • 二、大量数据插入

    • 2-1、三种处理方式
    • 2-1-1、单条循环插入
  • 2-1-2、修改SQL语句批量插入

  • 2-1-3、分批量多次循环插入

  • 2-2、插入速度慢的其他几种优化途径

  • 三、REPLACE INTO语法的“坑”

一、Insert的几种语法

============================================================================

1-1.普通插入语句


INSERT INTO table (a, b, c, ……) VALUES (‘a’, ‘b’, ‘c’, ……);

这里不再赘述,注意顺序即可,不建议小伙伴们去掉前面括号的内容,别问为什么,容易被同事骂。

在这里插入图片描述

1-2.插入或更新


如果我们希望插入一条新记录(INSERT),但如果记录已经存在,就更新该记录,此时,可以使用"INSERT INTO … ON DUPLICATE KEY UPDATE …"语句:

情景示例:这张表存了用户历史充值金额,如果第一次充值就新增一条数据,如果该用户充值过就累加历史充值金额,需要保证单个用户数据不重复录入。

这时可以使用"INSERT INTO … ON DUPLICATE KEY UPDATE …"语句。

注意事项:"INSERT INTO … ON DUPLICATE KEY UPDATE …"语句是基于唯一索引或主键来判断唯一(是否存在)的。如下SQL所示,需要在username字段上建立唯一索引(Unique),transId设置自增即可。

– 用户陈哈哈充值了30元买会员

INSERT INTO total_transaction (t_transId,username,total_amount,last_transTime,last_remark)

VALUES (null, ‘chenhaha’, 30, ‘2020-06-11 20:00:20’, ‘充会员’)

ON DUPLICATE KEY UPDATE total_amount=total_amount + 30, last_transTime=‘2020-06-11 20:00:20’, last_remark =‘充会员’;

– 用户陈哈哈充值了100元买瞎子至高之拳皮肤

INSERT INTO total_transaction (t_transId,username,total_amount,last_transTime,last_remark)

VALUES (null, ‘chenhaha’, 100, ‘2020-06-11 20:00:20’, ‘购买盲僧至高之拳皮肤’)

ON DUPLICATE KEY UPDATE total_amount=total_amount + 100, last_transTime=‘2020-06-11 21:00:00’, last_remark =‘购买盲僧至高之拳皮肤’;

若username='chenhaha'的记录不存在,INSERT语句将插入新记录,否则,当前username='chenhaha'的记录将被更新,更新的字段由UPDATE指定。

对了,ON DUPLICATE KEY UPDATE为MySQL特有语法,比如在MySQL迁移Oracle或其他DB时,类似的语句要改为MERGE INTO语法,兼容性让人想骂街。但没办法,就像用WPS写的xlsx用Office无法打开一样。

1-3.插入或替换


如果我们想插入一条新记录(INSERT),但如果记录已经存在,就先删除原记录,再插入新记录。

情景示例:这张表存的每个客户最近一次交易订单信息,要求保证单个用户数据不重复录入,且执行效率最高,与数据库交互最少,支撑数据库的高可用。

此时,可以使用"REPLACE INTO"语句,这样就不必先查询,再决定是否先删除再插入。

"REPLACE INTO"语句是基于唯一索引或主键来判断唯一(是否存在)的。

"REPLACE INTO"语句是基于唯一索引或主键来判断唯一(是否存在)的。

"REPLACE INTO"语句是基于唯一索引或主键来判断唯一(是否存在)的。

注意事项:如下SQL所示,需要在username字段上建立唯一索引(Unique),transId设置自增即可。

– 20点充值

REPLACE INTO last_transaction (transId,username,amount,trans_time,remark)

VALUES (null, ‘chenhaha’, 30, ‘2020-06-11 20:00:20’, ‘会员充值’);

– 21点买皮肤

REPLACE INTO last_transaction (transId,username,amount,trans_time,remark)

VALUES (null, ‘chenhaha’, 100, ‘2020-06-11 21:00:00’, ‘购买盲僧至高之拳皮肤’);

若username='chenhaha’的记录不存在,REPLACE语句将插入新记录(首次充值),否则,当前username='chenhaha’的记录将被删除,然后再插入新记录。

id不要给具体值,不然会影响SQL执行,业务有特殊需求除外。

小tips:

ON DUPLICATE KEY UPDATE:如果插入行出现唯一索引或者主键重复时,则执行旧的update;如果不会导致唯一索引或者主键重复时,就直接添加新行。

REPLACE INTO:如果插入行出现唯一索引或者主键重复时,则delete老记录,而录入新的记录;如果不会导致唯一索引或者主键重复时,就直接添加新行。

replace into 与 insert on deplicate udpate 比较:

  • 1、在没有主键或者唯一索引重复时,replace into 与 insert on deplicate udpate 相同。

  • 2、在主键或者唯一索引重复时,replace是delete老记录,而录入新的记录,所以原有的所有记录会被清除,这个时候,如果replace语句的字段不全的话,有些原有的比如c字段的值会被自动填充为默认值(如Null)。

  • 3、细心地朋友们会发现,insert on deplicate udpate只是影响一行,而REPLACE INTO可能影响多行,为什么呢?写在文章最后一节咯~

1-4.插入或忽略


如果我们希望插入一条新记录(INSERT),但如果记录已经存在,就啥事也不干直接忽略,此时,可以使用INSERT IGNORE INTO …语句:情景很多,不再举例赘述。

注意事项:同上,"INSERT IGNORE INTO …"语句是基于唯一索引或主键来判断唯一(是否存在)的,需要在username字段上建立唯一索引(Unique),transId设置自增即可。

– 用户首次添加

INSERT IGNORE INTO users_info (id, username, sex, age ,balance, create_time)

VALUES (null, ‘chenhaha’, ‘男’, 26, 0, ‘2020-06-11 20:00:20’);

– 二次添加,直接忽略

INSERT IGNORE INTO users_info (id, username, sex, age ,balance, create_time)

VALUES (null, ‘chenhaha’, ‘男’, 26, 0, ‘2020-06-11 21:00:20’);

二、大量数据插入

=======================================================================

2-1、三种处理方式


2-1-1、单条循环插入

我们取10w条数据进行了一些测试,如果插入方式为程序遍历循环逐条插入。在mysql上检测插入一条的速度在0.01s到0.03s之间。

逐条插入的平均速度是0.02*100000,也就是33分钟左右。

下面代码是测试例子:

1普通循环插入100000条数据的时间测试

@Test

public void insertUsers1() {

User user = new User();

user.setUserName(“提莫队长”);

user.setPassword(“正在送命”);

user.setPrice(3150);

user.setHobby(“种蘑菇”);

for (int i = 0; i < 100000; i++) {

user.setUserName(“提莫队长” + i);

// 调用插入方法

userMapper.insertUser(user);

}

}

执行速度是30分钟也就是0.018*100000的速度。可以说是很慢了

发现逐条插入优化成本太高。然后去查询优化方式。发现用批量插入的方法可以显著提高速度。

将100000条数据的插入速度提升到1-2分钟左右↓

2-1-2、修改SQL语句批量插入

insert into user_info (user_id,username,password,price,hobby)

values (null,‘提莫队长1’,‘123456’,3150,‘种蘑菇’),(null,‘盖伦’,‘123456’,450,‘踩蘑菇’);

用批量插入插入100000条数据,测试代码如下:

@Test

public void insertUsers2() {

List list= new ArrayList();

User user = new User();

user.setPassword(“正在送命”);

user.setPrice(3150);

user.setHobby(“种蘑菇”);

for (int i = 0; i < 100000; i++) {

user.setUserName(“提莫队长” + i);

// 将单个对象放入参数list中

list.add(user);

}

userMapper.insertListUser(list);

}

批量插入使用了0.046s 这相当于插入一两条数据的速度,所以用批量插入会大大提升数据插入速度,当有较大数据插入操作是用批量插入优化

批量插入的写法:

dao定义层方法:

Integer insertListUser(List user);

mybatis Mapper中的sql写法:

INSERT INTO db.user_info

( id,

username,

password,

price,

hobby)

values

(null,

#{item.userName},

#{item.password},

#{item.price},

#{item.hobby})

这样就能进行批量插入操作:

注:但是当批量操作数据量很大的时候。例如我插入10w条数据的SQL语句要操作的数据包超过了1M,MySQL会报如下错:

报错信息:

Mysql You can change this value on the server by setting the max_allowed_packet' variable. Packet for query is too large (6832997 > 1048576). You can change this value on the server by setting the max_allowed_packet' variable.

解释:

用于查询的数据包太大(6832997> 1048576)。 您可以通过设置max_allowed_packet的变量来更改服务器上的这个值。

通过解释可以看到用于操作的包太大。这里要插入的SQL内容数据大小为6M 所以报错。

解决方法:

数据库是MySQL57,查了一下资料是MySQL的一个系统参数问题:

max_allowed_packet,其默认值为1048576(1M),

查询:

最后

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Java工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助。

因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,不论你是刚入门Android开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门!

如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。**

[外链图片转存中…(img-ptwmeqv9-1715543912385)]

[外链图片转存中…(img-1g5dQzqu-1715543912385)]

[外链图片转存中…(img-BVQ2LiPB-1715543912386)]

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,不论你是刚入门Android开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门!

如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

  • 11
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值