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)
总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。
