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的,到时候可能出现总数和实际查询结果集的数量不一致的情况;

posted @ 2022-08-25 17:11  seeAll  阅读(1781)  评论(0编辑  收藏  举报