首页 > 其他分享 >批量查询必须进行批量操作

批量查询必须进行批量操作

时间:2024-06-04 15:15:52浏览次数:21  
标签:01 07 批量 batchSize 查询 123 user 2023 操作

批量新增

IService中的批量新增功能使用起来非常方便,但有一点注意事项,我们先来测试一下。 首先我们测试逐条插入数据:
@Test
void testSaveOneByOne() {
    long b = System.currentTimeMillis();
    for (int i = 1; i <= 100000; i++) {
        userService.save(buildUser(i));
    }
    long e = System.currentTimeMillis();
    System.out.println("耗时:" + (e - b));
}

private User buildUser(int i) {
    User user = new User();
    user.setUsername("user_" + i);
    user.setPassword("123");
    user.setPhone("" + (18688190000L + i));
    user.setBalance(2000);
    user.setInfo("{\"age\": 24, \"intro\": \"英文老师\", \"gender\": \"female\"}");
    user.setCreateTime(LocalDateTime.now());
    user.setUpdateTime(user.getCreateTime());
    return user;
}
执行结果如下: 可以看到速度非常慢。 然后再试试MybatisPlus的批处理:
@Test
void testSaveBatch() {
    // 准备10万条数据
    List<User> list = new ArrayList<>(1000);
    long b = System.currentTimeMillis();
    for (int i = 1; i <= 100000; i++) {
        list.add(buildUser(i));
        // 每1000条批量插入一次
        if (i % 1000 == 0) {
            userService.saveBatch(list);
            list.clear();
        }
    }
    long e = System.currentTimeMillis();
    System.out.println("耗时:" + (e - b));
}
执行最终耗时如下: 可以看到使用了批处理以后,比逐条新增效率提高了10倍左右,性能还是不错的。 不过,我们简单查看一下MybatisPlus源码:
@Transactional(rollbackFor = Exception.class)
@Override
public boolean saveBatch(Collection<T> entityList, int batchSize) {
    String sqlStatement = getSqlStatement(SqlMethod.INSERT_ONE);
    return executeBatch(entityList, batchSize, (sqlSession, entity) -> sqlSession.insert(sqlStatement, entity));
}
// ...SqlHelper
public static <E> boolean executeBatch(Class<?> entityClass, Log log, Collection<E> list, int batchSize, BiConsumer<SqlSession, E> consumer) {
    Assert.isFalse(batchSize < 1, "batchSize must not be less than one");
    return !CollectionUtils.isEmpty(list) && executeBatch(entityClass, log, sqlSession -> {
        int size = list.size();
        int idxLimit = Math.min(batchSize, size);
        int i = 1;
        for (E element : list) {
            consumer.accept(sqlSession, element);
            if (i == idxLimit) {
                sqlSession.flushStatements();
                idxLimit = Math.min(idxLimit + batchSize, size);
            }
            i++;
        }
    });
}
  可以发现其实MybatisPlus的批处理是基于PrepareStatement的预编译模式,然后批量提交,最终在数据库执行时还是会有多条insert语句,逐条插入数据。SQL类似这样:
Preparing: INSERT INTO user ( username, password, phone, info, balance, create_time, update_time ) VALUES ( ?, ?, ?, ?, ?, ?, ? )
Parameters: user_1, 123, 18688190001, "", 2000, 2023-07-01, 2023-07-01
Parameters: user_2, 123, 18688190002, "", 2000, 2023-07-01, 2023-07-01
Parameters: user_3, 123, 18688190003, "", 2000, 2023-07-01, 2023-07-01
  而如果想要得到最佳性能,最好是将多条SQL合并为一条,像这样:
INSERT INTO user ( username, password, phone, info, balance, create_time, update_time )
VALUES 
(user_1, 123, 18688190001, "", 2000, 2023-07-01, 2023-07-01),
(user_2, 123, 18688190002, "", 2000, 2023-07-01, 2023-07-01),
(user_3, 123, 18688190003, "", 2000, 2023-07-01, 2023-07-01),
(user_4, 123, 18688190004, "", 2000, 2023-07-01, 2023-07-01);
  该怎么做呢?   MySQL的客户端连接参数中有这样的一个参数:rewriteBatchedStatements。顾名思义,就是重写批处理的statement语句。参考文档: https://dev.mysql.com/doc/connector-j/8.0/en/connector-j-connp-props-performance-extensions.html#cj-conn-prop_rewriteBatchedStatements 这个参数的默认值是false,我们需要修改连接参数,将其配置为true   修改项目中的application.yml文件,在jdbc的url后面添加参数&rewriteBatchedStatements=true
spring:
  datasource:
    url: jdbc:mysql://127.0.0.1:3306/mp?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&serverTimezone=Asia/Shanghai&rewriteBatchedStatements=true
    driver-class-name: com.mysql.cj.jdbc.Driver
    username: root
    password: MySQL123
  再次测试插入10万条数据,可以发现速度有非常明显的提升: ClientPreparedStatementexecuteBatchInternal中,有判断rewriteBatchedStatements值是否为true并重写SQL的功能: 最终,SQL被重写了:

标签:01,07,批量,batchSize,查询,123,user,2023,操作
From: https://www.cnblogs.com/linzepro/p/18230744

相关文章

  • postgresql fdw 常用操作
    fdw--安装外部服务扩展createextensionpostgres_fdw;--创建外部服务createserverpostgres_serverforeigndatawrapperpostgres_fdwoptions(host'192.168.10.188',port'1521',dbname'testdb');--修改外部服务器配置--主机、端口和database这几项连接设......
  • 解锁 Java I/O 力量,一站式掌握文件操作、内存映射等黑科技
    大家好,今天我们来聊一聊Java中的I/O操作这个重要话题。作为一名资深Java开发者,深入掌握JavaI/O体系不仅可以让我们对文件、网络等资源操作游刃有余,更可以在一些场景下发挥其独特的性能优势。接下来,就让我为您一一拨开JavaI/O的神秘面纱!一、JavaI/O家族简......
  • ChatTTS 如何安装可视化操作
    可视化一键安装下载地址:百度网盘DownloadfromGitHub从GitHub下载代码。gitclonehttps://github.com/2noise/ChatTTS下载地址InstallDependencies在开始之前,请确保已安装必要的软件包。如果您尚未安装它们,可以使用pip进行安装:pipinstalltorchChatTTSIm......
  • tg机器人查询数据库在哪里:一文教你轻松定位数据库查询功能
    在使用TG机器人时,我们经常会需要查询数据库以获取所需的信息。但是,如何找到并定位这些数据库查询功能呢?本文将为你详细解答。一、理解机器人功能首先,你需要明确你正在使用的TG机器人是否具备数据库查询功能。这通常可以在机器人的介绍或官方文档中找到。如果机器人支持数据库......
  • AC自动机(查询)
        上面讲了AC自动机是如何建树和建自动机的,这里要讲的是AC自动机的查询和各个数组的功能和作用。    其实AC自动机的查询和KMP算法是及其相近的,都是一个指针跑主串,另一个指针跑ne串(这里就是回跳边)。    话都说到这了,不妨先来看看ne的真实用处吧。......
  • ### Python 字典操作详解:从创建、增删改查到高级技巧全解析
    1.创建字典使用大括号{}创建空字典empty_dict={}print(empty_dict)#输出:{}使用dict函数创建字典#通过键值对创建字典person=dict(name="Alice",age=30,city="NewYork")print(person)#输出:{'name':'Alice','age':30,'c......
  • 人大金仓创建序列,查询序列,修改序列
    1.创建序列:createsequenceseq_1INCREMENTBY1MINVALUE1STARTWITH1;序列指定为列的默认值:1.1直接在CREATETABLE命令中引用序列CREATETABLEtablename(idINT4DEFAULTnextval('myserial'));1.2更改表列以将其默认值设置为序列计数器ALTERTABLEtablenameAL......
  • ### Python 列表操作详解:从创建、增删到高级技巧全覆盖
    1.创建列表使用list函数创建空列表:empty_list=list()print(empty_list)#输出:[]从字符串创建列表:string="hello"list_from_string=list(string)print(list_from_string)#输出:['h','e','l','l','o']......
  • Git操作指南:多人协作提交代码的规范
    操作指南以TortoiseGit以例,多人或多台电脑之间同步协作少用gitpull,而是要通过以下方法右键点击gitsync,选择Fetch&Rebase等待Fetch完之后,在弹出来的选项中选择Rebase在Rebase窗口,点击StartRebaseFetch这步可以换成pull吗?因为rebase的时候,也是要merge的,不如提前me......
  • 【Python】使用 Python 查询域名的 IP 地址
    我们都已经长大好多梦正在飞就像童年看到的红色的蜻蜓我们都已经长大好多梦还要飞就像现在心目中红色的蜻蜓                     ......