thinkphp 5.1 分页需数据库层执行、透传查询参数、禁用全量统计并建联合索引:正确写法为链式调用 paginate(),配合 query 参数保留搜索条件,性能优化可关闭总数统计、添加索引或改用游标分页。

ThinkPHP 5.1 的分页功能非常轻量,一行 paginate() 就能搞定,但用错方式或忽略关键配置,容易导致性能下降、翻页丢参数、样式错乱等问题。核心不是“能不能分页”,而是“怎么分得稳、快、不掉链子”。
基础写法:控制器里直接链式调用
必须让 paginate() 接管整个查询过程,不能先 select() 再分页:
- ✅ 正确(数据库层分页):
$list = Db::name('user')->where('status', 1)->order('id desc')->paginate(10); - ❌ 错误(内存中分页,大数据量直接崩):
$data = Db::name('user')->select(); $list = $data->paginate(10);
模型写法同理:$list = UserModel::where('score', '>', 60)->paginate(15);
模板渲染:数据 + 分页 HTML 分开处理
控制器中 assign 后,模板里两件事要分开写:
- 循环当前页数据:
{volist name='list' id='user'} {$user.username} {/volist}或{foreach $list as $vo} {$vo.name} {/foreach} - 输出分页 HTML:
{$list->render()|raw}(|raw防止 HTML 被转义)
如需精简样式(比如只保留上一页/下一页),可用:{$list->simple()->render()|raw}
关键配置:避免翻页丢失搜索条件
带关键词、状态筛选的列表,翻页后 URL 参数清空是高频问题。解决方法是在 paginate() 第三个参数中透传请求参数:
- 自动获取全部 GET 参数:
paginate(10, false, ['query' => request()->param()]) - 手动指定某些参数:
paginate(10, false, ['query' => ['keyword' => $keyword, 'type' => $type]])
没加 query,点击第2页时 URL 就变成 /list?page=2,搜索条件全丢。
性能优化:十万级数据不卡顿
当用户翻到第200页以上,LIMIT 1990,10 会触发 MySQL 全表扫描前1990行。优化方向有三:
- 关总数统计:第二参数设为
false,跳过COUNT(*)查询; - 建联合索引:如按
user_id查+按create_time排序,建INDEX idx_uid_ctime (user_id, create_time); - 改游标分页:用
WHERE id 替代 offset,彻底避开深度偏移。
简单项目先做前两项,高并发或超大数据量建议上第三项。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











