赞
踩
在使用Mysql进行批量更新的时候,总会想哪一种方式效率更高,于是干脆进行了测试。
先说结论:
常见的四种方式有
当1w条记录分10次插入时,每种方式平均用时如下(编号对应上面的记录,单位是毫秒):
1:21392
2:318
3:221
4:241
当每次插入1w条,重复插入10次,每种方式评价用时如下(方式1直接淘汰不测了):
2:7678
3:919
4:804
所以,replace into 和update duplicate胜出
第0次,花费:1357 第1次,花费:191 第2次,花费:175 第3次,花费:230 第4次,花费:566 第5次,花费:142 第6次,花费:117 第7次,花费:122 第8次,花费:145 第9次,花费:135 平均花费:318 |
分析认为有可能是插入的是重复的id,有缓存加速的原因,后面几次很快,需要再测1w条记录分10次的情况分析,后者更实际
即单纯的一次多条update,需要在jdbc的url上加allowMultiQueries=true参数
速度巨慢,不参与1w条的测试
第0次,花费:23846 第1次,花费:23442 第2次,花费:22097 第3次,花费:19793 第4次,花费:19351 第5次,花费:20448 第6次,花费:22631 第7次,花费:19940 第8次,花费:19598 第9次,花费:22783 平均花费:21392 |
第0次,花费:1131 第1次,花费:96 第2次,花费:81 第3次,花费:77 第4次,花费:73 第5次,花费:308 第6次,花费:208 第7次,花费:86 第8次,花费:80 第9次,花费:78 平均花费:221 |
效率相当可观但是颇为危险,诸如有多个主键或主从表的情况容易造成错误
Mybatis 通过DUPLICATE实现在INSERT中批量高效更新数据_BasicLab基础架构实验室的博客-CSDN博客_mybatis duplicate
上面这篇博客相当不错
第0次,花费:1278 第1次,花费:174 第2次,花费:339 第3次,花费:98 第4次,花费:100 第5次,花费:83 第6次,花费:86 第7次,花费:80 第8次,花费:86 第9次,花费:87 平均花费:241 |
与replace相差无几
replace与duplicate都非常容易改变主键,而且是不可逆的改变,使用当慎重
第0次,花费:1330 第1次,花费:189 第2次,花费:199 第3次,花费:184 第4次,花费:236 第5次,花费:258 第6次,花费:169 第7次,花费:159 第8次,花费:209 第9次,花费:198 平均花费:313 |
变化不大,大概是有自适应索引等原因,速度依然不错
第0次,花费:1133 第1次,花费:108 第2次,花费:103 第3次,花费:96 第4次,花费:104 第5次,花费:70 第6次,花费:63 第7次,花费:94 第8次,花费:100 第9次,花费:217 平均花费:208 |
变化不大
第0次,花费:1141 第1次,花费:137 第2次,花费:88 第3次,花费:77 第4次,花费:87 第5次,花费:96 第6次,花费:86 第7次,花费:114 第8次,花费:117 第9次,花费:181 平均花费:212 |
第0次,花费:10300 第1次,花费:8184 第2次,花费:7537 第3次,花费:7256 第4次,花费:7336 第5次,花费:7260 第6次,花费:7145 第7次,花费:7249 第8次,花费:7276 第9次,花费:7242 平均花费:7678 |
第0次,花费:2140 第1次,花费:2007 第2次,花费:735 第3次,花费:560 第4次,花费:616 第5次,花费:594 第6次,花费:605 第7次,花费:722 第8次,花费:633 第9次,花费:587 平均花费:919 |
第0次,花费:1845 第1次,花费:808 第2次,花费:1652 第3次,花费:521 第4次,花费:604 第5次,花费:482 第6次,花费:534 第7次,花费:603 第8次,花费:481 第9次,花费:514 平均花费:804 |
下面列出本人测试时的代码与环境
mysql 8.0+
- DROP TABLE IF EXISTS `updatetest`;
- CREATE TABLE `updatetest` (
- `id` bigint(0) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 'id',
- `col1` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
- `col2` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
- `col3` int(0) UNSIGNED NOT NULL,
- `col4` int(0) UNSIGNED NOT NULL,
- `col5` char(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
- `gmt_create` datetime(0) NOT NULL DEFAULT CURRENT_TIMESTAMP(0),
- `gmt_modified` datetime(0) NOT NULL DEFAULT CURRENT_TIMESTAMP(0) ON UPDATE CURRENT_TIMESTAMP(0),
- PRIMARY KEY (`id`) USING BTREE
- ) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = REDUNDANT STORAGE MEMORY;
-
- SET FOREIGN_KEY_CHECKS = 1;
- @Mapper
- public interface UpdateMapper {
-
- void updateByMultiple(@Param("list") List<UpdatetestDO> list);
-
- void updateByCase(@Param("list") List<UpdatetestDO> list);
-
- void updateByReplace(@Param("list") List<UpdatetestDO> list);
-
- void updateByDuplicate(@Param("list") List<UpdatetestDO> list);
-
- void initInsert(@Param("list") List<UpdatetestDO> list);
- }
- <insert id="initInsert">
- insert into
- updatetest(col1, col2, col3, col4, col5)
- values
- <foreach collection="list" item="it" separator=",">
- (#{it.col1},#{it.col2},#{it.col3},#{it.col4},#{it.col5})
- </foreach>
- </insert>
-
- <update id="updateByMultiple">
- <foreach collection="list" item="it">
- update
- updatetest
- set
- col1=#{it.col1},
- col2=#{it.col2},
- col3=#{it.col3},
- col4=#{it.col4},
- col5=#{it.col5}
- where id=#{it.id};
- </foreach>
- </update>
-
- <update id="updateByCase">
- update
- updatetest
- <trim prefix="set" suffixOverrides=",">
- <foreach collection="list" item="it" open="col1 = case id" close="end,">
- when #{it.id} then #{it.col1}
- </foreach>
- <foreach collection="list" item="it" open="col2 = case id" close="end,">
- when #{it.id} then #{it.col2}
- </foreach>
- <foreach collection="list" item="it" open="col3 = case id" close="end,">
- when #{it.id} then #{it.col3}
- </foreach>
- <foreach collection="list" item="it" open="col4 = case id" close="end,">
- when #{it.id} then #{it.col4}
- </foreach>
- <foreach collection="list" item="it" open="col5 = case id" close="end,">
- when #{it.id} then #{it.col5}
- </foreach>
- </trim>
- WHERE id IN
- (<foreach collection="list" item="it" separator=",">
- #{it.id}
- </foreach>)
- </update>
- <insert id="updateByReplace">
- replace into
- updatetest(id,col1, col2, col3, col4, col5)
- values
- <foreach collection="list" item="it" separator=",">
- (#{it.id},#{it.col1},#{it.col2},#{it.col3},#{it.col4},#{it.col5})
- </foreach>
-
- </insert>
- <insert id="updateByDuplicate">
- insert into
- updatetest(id,col1, col2, col3, col4, col5)
- values
- <foreach collection="list" item="it" separator=",">
- (#{it.id},#{it.col1},#{it.col2},#{it.col3},#{it.col4},#{it.col5})
- </foreach>
- on duplicate key update
- col1=values(col1),
- col2=values(col2),
- col3=values(col3),
- col4=values(col4),
- col5=values(col5)
- </insert>
- @SpringBootTest
- @RunWith(SpringJUnit4ClassRunner.class)
- public class FrameApplicationTests {
- @Autowired
- UpdateMapper mapper;
-
- @Test
- public void initInsert() {
- ArrayList<UpdatetestDO> dos = new ArrayList<>();
- for (long i = 1001L; i <= 10000L; i++) {
- UpdatetestDO it = new UpdatetestDO("col1" + i, "col2" + i, i, i, "col5" + i);
- dos.add(it);
- }
- mapper.initInsert(dos);
- }
-
- @Test
- public void caseTest(){
- long all=0;
- for (int cnt = 0; cnt < 10; cnt++) {
-
- ArrayList<UpdatetestDO> dos = new ArrayList<>();
- for (long i = 1L; i <= 10000L; i++) {
- UpdatetestDO it = new UpdatetestDO("col1:"+cnt+":" + i, "col2:case:" + i, i, i, "col5:cnt:" + i);
- it.setId(i);
- dos.add(it);
- }
- long start = System.currentTimeMillis();
- mapper.updateByCase(dos);
- long end = System.currentTimeMillis();
- long spend=end-start;
- System.out.println("第"+cnt+"次,花费:"+spend);
- all+=spend;
-
- }
- System.out.println("平均花费:"+all/10);
- }
-
- @Test
- public void multipleTest(){
- long all=0;
- for (int cnt = 0; cnt < 10; cnt++) {
- int base=cnt*1000;
- ArrayList<UpdatetestDO> dos = new ArrayList<>();
- for (long i = 1L; i <= 1000L; i++) {
- UpdatetestDO it = new UpdatetestDO("col1:"+base+":" + i, "col2:mul" + i, i, i, "col5:cnt:" + i);
- it.setId(base+i);
- dos.add(it);
- }
- long start = System.currentTimeMillis();
- mapper.updateByMultiple(dos);
- long end = System.currentTimeMillis();
- long spend=end-start;
- System.out.println("第"+cnt+"次,花费:"+spend);
- all+=spend;
- }
- System.out.println("平均花费:"+all/10);
- }
-
- @Test
- public void replaceTest(){
- long all=0;
- for (int cnt = 0; cnt < 10; cnt++) {
- ArrayList<UpdatetestDO> dos = new ArrayList<>();
- for (long i = 1L; i <= 10000L; i++) {
- UpdatetestDO it = new UpdatetestDO("col1:"+cnt+":" + i, "col2:rep:" + i, i, i, "col5:cnt:" + i);
- it.setId(i);
- dos.add(it);
- }
- long start = System.currentTimeMillis();
- mapper.updateByReplace(dos);
- long end = System.currentTimeMillis();
- long spend=end-start;
- System.out.println("第"+cnt+"次,花费:"+spend);
- all+=spend;
- }
- System.out.println("平均花费:"+all/10);
- }
-
- @Test
- public void duplicateTest(){
- long all=0;
- for (int cnt = 0; cnt < 10; cnt++) {
- ArrayList<UpdatetestDO> dos = new ArrayList<>();
- for (long i = 1L; i <= 10000L; i++) {
- UpdatetestDO it = new UpdatetestDO("col1:"+cnt+":" + i, "col2:dup:" + i, i, i, "col5:cnt:" + i);
- it.setId(i);
- dos.add(it);
- }
- long start = System.currentTimeMillis();
- mapper.updateByDuplicate(dos);
- long end = System.currentTimeMillis();
- long spend=end-start;
- System.out.println("第"+cnt+"次,花费:"+spend);
- all+=spend;
- }
- System.out.println("平均花费:"+all/10);
- }
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。