MyBatis Plus大数据量查询慢原因分析及解决
作者:night_gu
大数据量查询慢常因全表扫描、分页不当、索引缺失、内存占用高及ORM开销,优化措施包括分页查询、流式读取、SQL优化、批处理、多数据源、结果集二次处理及配置调优
大数据量查询慢的常见原因
MyBatis Plus 在处理大数据量查询时,性能瓶颈通常出现在数据库连接、网络传输、内存消耗和结果集处理等方面。
常见问题包括全表扫描、未合理使用分页、ORM 映射开销过大等。
优化方案
合理使用分页查询
MyBatis Plus 内置分页插件(PaginationInnerInterceptor
),避免一次性加载全部数据。
配置示例:
@Configuration public class MybatisPlusConfig { @Bean public MybatisPlusInterceptor mybatisPlusInterceptor() { MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL)); return interceptor; } }
查询时通过 Page
对象分页:
Page<User> page = new Page<>(1, 100); // 当前页, 每页条数 userMapper.selectPage(page, null);
启用流式查询
通过 @Options
注解启用 JDBC 流式读取,减少内存占用:
@Select("SELECT * FROM large_table") @Options(resultSetType = ResultSetType.FORWARD_ONLY, fetchSize = 1000) @ResultType(User.class) void selectLargeData(ResultHandler<User> handler);
使用游标处理结果
结合 MyBatis 的 Cursor
逐行处理数据:
try (Cursor<User> cursor = userMapper.selectCursor(null)) { cursor.forEach(user -> { // 单行处理逻辑 }); }
SQL 语句优化
添加必要的索引,避免 SELECT *
,只查询必要字段。通过 @SqlParser
注解过滤逻辑删除等干扰:
@SqlParser(filter = true) @Select("SELECT id, name FROM user WHERE status = 1") List<User> selectActiveUsers();
批处理操作
插入/更新时使用 saveBatch
方法,通过 rewriteBatchedStatements=true
参数提升批量性能:
List<User> userList = ... // 大数据集合 userService.saveBatch(userList, 1000); // 每批1000条
高级方案
多数据源与读写分离
通过 @DS
注解将查询路由到从库,减轻主库压力:
@DS("slave") @Select("SELECT * FROM read_heavy_table") List<Record> selectReadHeavyData();
结果集二次处理
在内存充足的情况下,先通过 LIMIT
分页查询 ID,再通过 IN
查询完整数据:
-- 第一步:查询ID范围 SELECT id FROM large_table LIMIT 1000000, 1000; -- 第二步:精确获取数据 SELECT * FROM large_table WHERE id IN (1,2,3...);
配置调优
在 application.yml
中调整连接池参数:
spring: datasource: hikari: maximum-pool-size: 20 connection-timeout: 30000 idle-timeout: 600000 max-lifetime: 1800000
监控与诊断
启用 p6spy
监控实际执行的 SQL,分析慢查询日志:
<dependency> <groupId>p6spy</groupId> <artifactId>p6spy</artifactId> <version>3.9.1</version> </dependency>
配置 spy.properties
记录执行时间:
appender=com.p6spy.engine.spy.appender.Slf4JLogger logMessageFormat=com.p6spy.engine.spy.appender.CustomLineFormat customLogMessageFormat=%(executionTime) ms | %(category) | %(sql)
总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。