最近在学习分页技术,发现偏移分页和滚动分页是两种完全不同的思路。记录一下我的理解和思考。
偏移分页就是我们最常见的分页方式,通过页码来翻页。
实现原理:
-- 第1页:跳过0条,取10条
SELECT * FROM users LIMIT 10 OFFSET 0;
-- 第2页:跳过10条,取10条
SELECT * FROM users LIMIT 10 OFFSET 10;
-- 第3页:跳过20条,取10条
SELECT * FROM users LIMIT 10 OFFSET 20;
页面效果:
[上一页] [1] [2] [3] [4] [5] [下一页]
用户可以直接跳到任意页码,很灵活。
滚动分页就像微博、朋友圈那样,往下滑就自动加载更多内容。
实现原理:
-- 第一次加载:从ID最大的开始取
SELECT * FROM users ORDER BY id DESC LIMIT 10;
-- 加载更多:从上次最小的ID继续取
SELECT * FROM users WHERE id < 1050 ORDER BY id DESC LIMIT 10;
-- 再加载更多:继续往前取
SELECT * FROM users WHERE id < 1040 ORDER BY id DESC LIMIT 10;
页面效果:
[已有内容]
[新加载的内容]
[加载更多按钮] 或者 [自动加载]
用户只能往下滚动,不能跳页。
偏移分页:
滚动分页:
偏移分页的问题:
-- 翻到第1000页时
SELECT * FROM users LIMIT 10 OFFSET 9990;
数据库是怎么"跳过"的?
实际上数据库不是真的"数数跳过",而是这样处理的:
为什么越往后越慢?
第1页:OFFSET 0 → 直接开始取数据,很快
第10页:OFFSET 90 → 需要跳过90条,稍慢
第100页:OFFSET 990 → 需要跳过990条,明显慢了
第1000页:OFFSET 9990 → 需要跳过9990条,巨慢!
就像你要找一本厚书的第800页,即使你知道页码,也得从前面翻过去,不能直接跳到第800页。
页数越大越慢!
滚动分页的优势:
-- 不管加载多少次,都是这样
SELECT * FROM users WHERE id < 某个值 ORDER BY id DESC LIMIT 10;
每次都是直接定位,不需要跳过前面的数据,速度稳定。
偏移分页的困扰: 假设用户在看第2页,这时有新数据插入到第1页:
滚动分页的稳定性: 因为是基于ID或时间戳来分页,新插入的数据不会影响已经加载的内容。
例子:
例子:
问题: OFFSET太大时性能差
解决方案:
-- 不要用OFFSET,改用WHERE条件
-- 假设上一页最后一条记录的ID是100
SELECT * FROM users WHERE id > 100 ORDER BY id LIMIT 10;
但这样就失去了"跳页"的能力。
关键点:
代码示例:
// 前端记录游标
let lastId = null;
function loadMore() {
const url = lastId
? `/api/users?lastId=${lastId}&limit=10`
: `/api/users?limit=10`;
fetch(url).then(response => {
const users = response.data;
if (users.length > 0) {
lastId = users[users.length - 1].id;
}
// 追加到页面
appendUsers(users);
});
}
什么时候用偏移分页:
什么时候用滚动分页:
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。