0%

大数据量 Mybatis 分页插件Count语句优化

问题

当在大数量的情况下,进行分页查询,统计总数时,会自动count一次,这个语句是在我们的查询语句的基础上嵌套一层,如:

1
SELECT COUNT(*) FROM (主sql)

这样在数据量大的情况下,会出问题,很容易cpu就跑满了

优化

在mapper.xml中自定义count查询,使用自定义的查询速度会快些

增加countSuffixcount 查询后缀配置参数,该参数是针对PageInterceptor配置的,默认值为_COUNT

分页插件会优先通过当前查询的 msId +countSuffix查找手写的分页查询。

如果存在就使用手写的 count 查询,如果不存在,仍然使用之前的方式自动创建 count 查询。

例如,如果存在下面两个查询:

1
2
3
4
5
6
7
8

select a.id,b.countryname,a.countrycode from country a
left join country b on a.id = b.id
order by a.id


select count(distinct a.id) from country a
left join country b on a.id = b.id

上面的countSuffix使用的默认值_COUNT,分页插件会自动获取到selectLeftjoin_COUNT查询,这个查询需要自己保证结果数正确。

返回值的类型必须是resultType="Long",入参使用的和selectLeftjoin查询相同的参数,所以在 SQL 中要按照selectLeftjoin的入参来使用。

因为selectLeftjoin_COUNT方法是自动调用的,所以不需要在接口提供相应的方法,如果需要单独调用,也可以提供。

上面方法执行输出的部分日志如下:

1
2
3
4
5
6
7
8
9
10
11
12
DEBUG [main] - ==>  Preparing: select count(distinct a.id) from country a left join country b on a.id = b.id 
DEBUG [main] - ==> Parameters:
TRACE [main] - <== Columns: C1
TRACE [main] - <== Row: 183
DEBUG [main] - <== Total: 1
DEBUG [main] - Cache Hit Ratio [com.github.pagehelper.mapper.CountryMapper]: 0.0
DEBUG [main] - ==> Preparing: select a.id,b.countryname,a.countrycode from country a left join country b on a.id = b.id order by a.id LIMIT 10
DEBUG [main] - ==> Parameters:
TRACE [main] - <== Columns: ID, COUNTRYNAME, COUNTRYCODE
TRACE [main] - <== Row: 1, Angola, AO
TRACE [main] - <== Row: 2, Afghanistan, AF
TRACE [main] - <== Row: 3, Albania, AL

此功能pagehelper5.0.4版本以上支持,所以要升级pagehelper版本

升级后单元测试报错

1
Cause: java.lang.ClassCastException: com.github.pagehelper.PageHelper cannot be cast to org.apache.ibatis.plugin.Interceptor;

原因

1
2
3
5.*使用新的分页com.github.pagehelper.PageInterceptor

helperDialect 分页插件会自动检测当前的数据库链接,自动选择合适的分页方式。 你可以配置`helperDialect`属性来指定分页插件使用哪种方言。

解决方案

1
修改mybatis-Config.xml
1
2
3
4
5
6
7
Caused by: com.github.pagehelper.PageException: java.lang.NoSuchMethodException: org.apache.ibatis.reflection.MetaObject.forObject(java.lang.Object)
at com.github.pagehelper.util.MetaObjectUtil.(MetaObjectUtil.java:49)
... 57 more
Caused by: java.lang.NoSuchMethodException: org.apache.ibatis.reflection.MetaObject.forObject(java.lang.Object)
at java.lang.Class.getDeclaredMethod(Class.java:2017)
at com.github.pagehelper.util.MetaObjectUtil.(MetaObjectUtil.java:47)
... 57 more

原因

1
mybatis版本太低导致分页插件拦截器里面反射失败

解决方案

1
升级mybatis 版本为:3.4.4 、升级mybatis-spring版本为:1.3.0