MySQL 和 Redis 偏移量分页在数据增删场景下的问题与解决方案

一、问题背景:偏移量分页(Offset-based Pagination)的固有缺陷

无论是 MySQL 的 LIMIT offset, size,还是 Redis 的 ZRANGE key start stop,它们都基于结果集中的位置(偏移量)进行分页,而非基于数据本身的值。
当数据发生
插入或删除
时,结果集中后续元素的位置会发生变化,从而导致分页结果异常。


二、具体问题表现

1. MySQL 中的问题
(1)数据删除 → 跳过记录
-- 初始数据
SELECT * FROM users ORDER BY id;
-- id | name
-- ---+-----
-- 1  | A
-- 2  | B
-- 3  | C
-- 4  | D
-- 5  | E

-- 第一页(LIMIT 0,2)
SELECT * FROM users ORDER BY id LIMIT 0, 2;
-- 1 | A
-- 2 | B

-- 删除 id=2
DELETE FROM users WHERE id = 2;

-- 第二页(LIMIT 2,2)
SELECT * FROM users ORDER BY id LIMIT 2, 2;
-- 4 | D   ← 跳过了 id=3(C)
-- 5 | E

原因:删除后,原第3条(C)变为第2条,但 LIMIT 2,2 跳过了前2条,直接从第3条开始取,导致 C 被跳过。

(2)数据新增 → 重复显示
-- 第一页
SELECT * FROM users ORDER BY id LIMIT 0, 2;
-- 1 | A
-- 2 | B

-- 新增一条 id=1.5 的记录(按 id 排序插入中间)
INSERT INTO users VALUES (1.5, 'A1');

-- 第二页
SELECT * FROM users ORDER BY id LIMIT 2, 2;
-- 2 | B   ← 已在第一页出现,现在又出现在第二页
-- 3 | C

原因:新增数据改变了原有记录的位置,B 从第2位变为第3位,被第二页再次包含。


2. Redis Sorted Set(ZSET)中的类似问题
(1)删除元素 → 跳过
# 初始
ZADD users 1 "A" 2 "B" 3 "C" 4 "D" 5 "E"

# 第一页
ZRANGE users 0 1
# "A", "B"

# 删除 "B"
ZREM users "B"

# 第二页
ZRANGE users 2 3
# "D", "E"  ← 跳过了 "C"
(2)新增元素 → 重复
# 第一页
ZRANGE users 0 1"A", "B"

# 新增分数 1.5 的 "A1"
ZADD users 1.5 "A1"

# 第二页
ZRANGE users 2 3"B", "C""B" 重复出现

根本原因一致ZRANGE 基于索引位置,而非分数或成员值本身。


三、问题本质总结

问题类型表现根本原因
数据删除后续记录被跳过偏移量固定,但数据前移
数据新增已展示数据重复出现新数据插入导致原有数据后移,被后续页再次包含

🔍 核心缺陷:分页依赖“位置”,而非“数据标识”。


四、解决方案:游标分页(Cursor-based Pagination)

使用上一页最后一条记录的排序字段值作为下一页的起点,避免依赖偏移量。

✅ MySQL 游标分页示例
-- 第一页
SELECT * FROM users ORDER BY id LIMIT 2;
-- 假设最后一条 id = 2

-- 第二页:从 id > 2 开始查
SELECT * FROM users WHERE id > 2 ORDER BY id LIMIT 2;
-- 返回 id=3(C), 4(D) —— 不受中间增删影响

要求:排序字段需唯一且有序(如自增ID、时间戳等)。

✅ Redis 游标分页示例(基于分数)
# 第一页:取分数最小的2个
ZRANGEBYSCORE users -inf +inf LIMIT 0 2
# 假设最大分数为 2("B")

# 第二页:从分数 > 2 开始取
ZRANGEBYSCORE users (2 +inf LIMIT 0 2
# 返回 "C"(3), "D"(4)

使用 (score 表示“开区间”,避免重复。


五、优势对比

方式是否受增删影响是否支持跳页适用场景
偏移量分页(LIMIT / ZRANGE)❌ 是✅ 支持数据静态、小规模、需跳页
游标分页(WHERE id > ? / ZRANGEBYSCORE)✅ 否❌ 不支持(只能顺序翻页)动态数据、高性能、无限滚动

六、结论

在数据频繁变动的场景下,应优先使用游标分页(Cursor-based Pagination)替代传统的偏移量分页,以确保分页结果的一致性、完整性与稳定性

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值