LINDEX / LSET 是什么
LINDEX 按下标读取列表元素,LSET 按下标改写已存在的元素,两者都支持负数下标(-1 为最后一个元素)。关键要记住 List 的底层是双向链表式结构:头尾操作 O(1),按下标访问中间元素需要逐个走,代价 O(N)。因此越界读取返回 nil 而不报错,越界写入则直接报 index out of range。
基本信息
| 适用版本 | Redis 全版本 |
|---|---|
| LINDEX key index | 按下标取值,O(N);越界返回 nil |
| LSET key index value | 按下标改写,O(N);越界报错 |
| 负数下标 | -1 最后一个,-2 倒数第二个,以此类推 |
| 头尾操作 | LPUSH/RPUSH/LPOP/RPOP 均为 O(1) |
| 替代方案 | 随机访问密集场景用 Hash 或 ZSet 存储 |
典型使用场景
- 查看队列最新或最早的一条记录:LINDEX key 0 或 -1
- 修正队列中的单个元素:定位后原地改写,不重建整个列表
- 任务状态数组的定点更新:小列表上改写某个位置的状态标记
- 调试列表内容:快速确认某下标上的实际元素
- 与 LRANGE 配合实现分页读取
示例
示例
RPUSH letters a b c
LINDEX letters 0 # a
LINDEX letters -1 # c
LINDEX letters 99 # nil:越界读取不报错
LSET letters 1 B # OK,列表变 a B c
LSET letters 9 x # ERR index out of range:越界写入直接失败
LLEN letters # 先确认长度,再决定下标是否合法
LRANGE letters 0 -1 # 全量查看,用于核对改写结果操作代价对照
| 操作 | 复杂度 | 适用提示 |
|---|---|---|
| LINDEX 取头尾 | 接近 O(1) | 获取队首队尾元素的最快做法 |
| LINDEX 取中间 | O(N) | 列表越长越慢,避免高频调用 |
| LSET 改写 | O(N) | 只能改写已存在的下标,不自动扩容 |
| LRANGE 分页 | O(S+N) | S 为起始偏移,偏移越大越慢 |
| LPOP/RPUSH | O(1) | 队列与栈场景优先使用头尾操作 |
需要按下标随机访问大量数据时,说明数据结构选错了:List 更适合队列、栈、时间线这类只在两端操作的场景;随机访问密集的业务应改用 Hash(按字段读)或 ZSet(按 score 读)。
LSET 不会自动扩容:对不存在的位置写入会直接报错。批量更新前先用 LLEN 校验长度,或改用 LPUSH/RPUSH 追加,避免脚本中途失败留下半更新状态。