数据量大的情况下 Laravel 获取分页查询时很慢,有什么优化方案?

数据量大的情况下 Laravel 获取分页查询时很慢,有什么优化方案?

Laravel

上面第一条 SQL 是 laravel 分页时用来获取数据总数的,第二条是获取当前页数据的。
第一条竟然要三百多毫秒,第二条1毫秒都不用。users 数据表有200万行数据,这种情况有什么解决方案没,大家是如何优化的

《L03 构架 API 服务器》
你将学到如 RESTFul 设计风格、PostMan 的使用、OAuth 流程,JWT 概念及使用 和 API 开发相关的进阶知识。
《L04 微信小程序从零到发布》
从小程序个人账户申请开始,带你一步步进行开发一个微信小程序,直到提交微信控制台上线发布。
最佳答案

增加一个搜索项:创建日期,默认是最近几天,然后创建时间加索引

3天前 评论
h-o-o (楼主) 2天前
xiaogui 10小时前
讨论数量: 23

count慢导致的,自己写不用它的

1周前 评论
h-o-o (楼主) 1周前
thus (作者) 1周前
loading-ss 1周前

直接不获取数据总数,不做页码就好了,只做上一页下一页

1周前 评论
h-o-o (楼主) 1周前
wanghan 1周前

数据量大时候的limit也有性能问题

1周前 评论
h-o-o (楼主) 1周前
pigzzz (作者) 1周前
h-o-o (楼主) 1周前
Lichmaker 6天前
h-o-o (楼主) 6天前

覆盖索引可否?

1周前 评论
h-o-o (楼主) 1周前
不朽 (作者) 1周前
h-o-o (楼主) 1周前
不朽 (作者) 1周前
不朽 (作者) 1周前

数据量多大?

1周前 评论
h-o-o (楼主) 1周前
Epona

可以试试。select count(id)*的话肯定慢的。

1周前 评论
h-o-o (楼主) 1周前
anniversary 1周前

300毫秒有什么大惊小怪的,那你是没见过我们公司十几秒的接口

1周前 评论
Artist0618 1周前
h-o-o (楼主) 1周前
晓轩 (作者) 1周前

mysql,又是简单的select的话 可以试试 explain select * from user?

\DB::select('explain select id from user;');

返回值有个rows

1周前 评论
wanghan 1周前
Lichmaker 6天前

@izudo 这个查询还有误差的吗?

    $explain = DB::select('explain select id from users');
    $count = DB::select('select count(*) as aggregate from `users`');
    return $explain[0]->rows . ' - ' . $count[0]->aggregate; // 输出 1959223 - 1999997
1周前 评论

@izudo
还有个问题就是,无论 'explain select' 查询多少行,无论是1行还是200万行,其执行时间基本都不变。

file

file

1周前 评论

@h-o-o 好像有误差,这也是我网上搜的方法,explain 本来只是mysql用来分析sql语句执行情况用的。
还有一个方法就是 通过mysql 的information_schema表来查询

\DB::select('select * from information_schema.`TABLES` as t where t.TABLE_NAME=\'user\';');
1周前 评论
h-o-o (楼主) 1周前
izudo (作者) 1周前
h-o-o (楼主) 1周前

200W就叫海量了?

1周前 评论

这个应该是第一次连接耗时也含进去了吧,你在执行分页之前再执行一个查询看看时间 :joy:

1周前 评论
h-o-o (楼主) 1周前

@h-o-o

在model里写个方法

public function getRowCount()
{
    $database = env('DB_DATABASE', config('database.connections.mysql.database'));
    $r = \DB::select("select * from information_schema.`TABLES` as t where t.TABLE_NAME='{$this->table}' and TABLE_SCHEMA='{$database}';");
    return $r[0]->TABLE_ROWS ?? 0;
}

仅用于mysql,还得有information_schema这个表的访问权限
有表前缀的话,把方法里的表名那处理下就好了

1周前 评论
h-o-o (楼主) 1周前
izudo (作者) 1周前
h-o-o (楼主) 1周前

200w数据,一定要全部展示出来吗,我想没有人会闲到一页一页点,点到200w吧,只展示部分数据,其他的通过条件过滤再查询出来,这样不是挺好吗,我这边系统里,SaaS后台订单列表1000多万,只展示最新的50w

1周前 评论

评论了就别删除啊?

file
戾气这么重?

1周前 评论
h-o-o (楼主) 1周前

@MayTsing 我也觉得是第一次连接耗时也算进去了

1周前 评论

说实在的,200万的数据真的不是很大。mysql的话千万级别的数据也勉强可以顶住。有没有考虑过服务器的原因(自己猜测而已)

1周前 评论
h-o-o (楼主) 6天前
h-o-o (楼主) 6天前

InnoDB 引擎的话,从SQL 层面没法优化!那些说 count(id) 的属于误导。

在 InnoDB 存储引擎中,primary key 是 clustered index(最大的索引),使用它来处理 select count(*) from table_name 最慢。

你可以考虑对总数进行缓存,插入和删除维护一下缓存的总数就行了。或者使用数据表统计的近似值。
然后在控制器里 使用 return new \Illuminate\Pagination\LengthAwarePaginator($data, $total, 15, 1);

6天前 评论

分页自己写,select * from users where id > last_id limit 10 理论上没毛病

5天前 评论
h-o-o (楼主) 5天前

我个人认为,百万的数据其实也不算小,sql在怎么优化,分页count都会耗时的,建议跟楼上的一样,第一次先查出来总数,缓存出来,insert和del时,对总数修改就可以..

5天前 评论

增加一个搜索项:创建日期,默认是最近几天,然后创建时间加索引

3天前 评论
h-o-o (楼主) 2天前
xiaogui 10小时前

如果一定需要count总数的话 我觉得课可以用异步处理好存放在redis上

1天前 评论

请勿发布不友善或者负能量的内容。与人为善,比聪明更重要!