PageHelper(含低版本)自定义count
一、概述
PageHelper:com.github.pagehelper.PageHelper
二、问题描述
有一个分页需求,总数据有11万多,响应时间为3秒,测试提出了bug,响应时间太长。
sql如下:
a表有11万多数据,其他表数据很少
SELECT COUNT(0) FROM table_a a LEFT JOIN table_b b ON b.ref_a_id = a.id LEFT JOIN table_c c ON c.ref_a_id = a.id LEFT JOIN table_d d ON d.ref_a_id = a.id LEFT JOIN table_e e ON e.ref_a_id = a.id LEFT JOIN table_f f ON f.ref_a_id = a.id WHERE a.deleted = 0 AND a.enabled = 1...
SELECT * FROM table_a a LEFT JOIN table_b b ON b.ref_a_id = a.id LEFT JOIN table_c c ON c.ref_a_id = a.id LEFT JOIN table_d d ON d.ref_a_id = a.id LEFT JOIN table_e e ON e.ref_a_id = a.id LEFT JOIN table_f f ON f.ref_a_id = a.id WHERE a.deleted = 0 AND a.enabled = 1...
给on后面的条件加了索引之后,响应时间减少到1.5秒;
count耗时1.15秒,select * 耗时0.35秒,就奇了怪了,count为什么比select * 还耗时呢?
就研究count的sql,看explain执行计划,也都有索引的感觉;数据库方面比较薄弱,百度了很久,此刻也说不出个所以然;
但是,我每注释一个left join,耗时就会少个0.18秒左右:
1.126
0.935 少0.191
0.722 少0.213
0.545 少0.177
0.387 少0.158
0.217 少0.170
那么,如果count的sql少几个left join也是可以降低响应时间的,按道理在我这边业务上left join都是1对1的,count的时候确实不需要。
三、解决
1,高版本PageHelper的处理方式
百度:PageHelper自定义count
版本要5.0.4;简单说,就是除了写分页查询的sql,再写一个count的sql(id等于查询的sql拼接_COUNT),这样框架查询总数的时候会使用你写的count的sql;
2,低版本PageHelper的处理方式
像我的版本是4.1.6,升级到5.0.4又会报很多错,即使不报错,也存在一定的风险;
可以这么做:
原先的代码:
int pageNum = 1; int pageSize = 20; PageHelper.orderBy("a.create_time desc"); PageHelper.startPage(pageNum, pageSize); List list = 分页查询的sql; PageInfo pageInfo = new PageInfo<>(list);
修改后的代码:
int pageNum = 1; int pageSize = 20; PageHelper.orderBy("a.create_time desc"); PageHelper.startPage(pageNum, pageSize, false); List list = 分页查询的sql; // 自定义统计数量 long count = PageHelper.count(new ISelect() { @Override public void doSelect() { count的sql; } }); if (list instanceof Page) { Page page = (Page) list; page.setTotal(count); } // 最终的分页对象,和原先不使用自定义count的sql的时候一样 PageInfo pageInfo = new PageInfo<>(list);
四、总结
PageHelper.count(ISelect select)方法要放在最后面,防止影响框架执行分页查询的sql;
count的sql,不用写成select count(0) from,写成select a.id from就行了;记得debug这个sql,看是否符合自己的预期,因为PageHelper有时候会对sql进行优化,可能你配置了某个优化参数等等;
适不适合用自定义count,风险要评估好,毕竟谁也不能保证left join就是1对1的,到时候可能出现总数和实际查询结果集的数量不一致的情况;