Redis 数据类型在商超的使用场景及详细分析

1. 各数据类型在商超环境的核心使用场景总述

1.1. String 类型

作为 Redis 最基础的数据类型,适用于存储单一键值对,在商超中主要用于简单数据缓存(如商品库存、价格、会员积分)、计数器(如每日销售额、实时访客数)、分布式锁(如秒杀活动防超卖)等场景,因其操作简单、性能高效,成为高频访问数据的首选存储方式。

1.2. Hash 类型

适合存储包含多个字段的对象数据,在商超中多用于商品详情存储(名称、价格、库存、产地等多属性)、会员信息缓存(姓名、等级、绑定手机号等)、订单快照(订单号、商品列表、金额等),可单独操作某个字段,避免整对象更新的资源浪费。

1.3. List 类型

基于双向链表实现,支持有序插入和弹出,在商超中主要用于消息队列(如订单处理队列、支付结果通知队列)、时序数据存储(如最新上架商品列表、最近 10 笔订单记录)、限流控制(如接口访问频率限制),适合需要 FIFO(先进先出)或 LIFO(后进先出)逻辑的场景。

1.4. Set 类型

无序且元素唯一的集合,在商超中用于会员标签管理(如 “高消费”“高频次” 标签的添加与查询)、活动参与人员去重(如同一会员多次报名只算一次)、用户行为分析(如同时购买 A 和 B 商品的会员交集),利用集合运算(交集、差集)实现精准营销。

1.5. Sorted Set 类型

通过分数排序的有序集合,在商超中核心用于排行榜(如商品销量 Top10、会员积分排行)、范围查询(如积分 1000-5000 的会员筛选)、延迟任务(如订单超时未支付自动取消),结合分数的原子更新特性,适合需要动态排序和范围统计的场景。

1.6. Bitmap 类型

以位为单位存储数据,极致节省内存,在商超中用于签到记录(会员每日签到状态)、用户行为标记(如是否浏览过某商品、是否参与过活动)、活跃会员统计(按天 / 周统计活跃会员数),尤其适合海量用户的二进制状态记录。

1.7. HyperLogLog 类型

用于基数统计(不重复元素数量),在商超中主要用于独立访客(UV)统计(每日 / 每月访问网站的独立用户数)、商品被浏览的独立用户数活动参与的独立会员数,以极小的内存消耗支持海量数据的近似计数。

2. 获取数据类型与时间复杂度说明

2.1 时间复杂度说明

  • O(1):操作时间与数据量无关,性能最优(如 String 的 GET/SET、Hash 的 HGET)。
  • O(log n):操作时间随数据量对数增长,适合大数据量场景(如 Sorted Set 的 ZADD/ZRANK)。
  • O(n):操作时间随数据量线性增长,需控制数据规模(如 List 的 LRANGE、Set 的 SADD 多元素)。
  • O(k):操作时间取决于返回 / 处理的元素数量 k(如 List 的 LRANGE 返回 k 个元素)。
商超场景中,优先选择 O (1) 和 O (log n) 的操作(如库存更新、销量排行),对 O (n) 操作需限制数据量(如 List 最多保留 1000 条记录),避免性能瓶颈。

2.2 查询不同键的类型

# 1. 查询 String 类型键
127.0.0.1:6379> TYPE sku:10001  # 假设是单个 SKU 的 JSON 字符串
string

# 2. 查询 Hash 类型键
127.0.0.1:6379> TYPE skus  # 假设是存储所有 SKU 的 Hash 表
hash

# 3. 查询 List 类型键(如购物车列表)
127.0.0.1:6379> TYPE cart:1001
list

# 4. 查询 Set 类型键(如商品标签集合)
127.0.0.1:6379> TYPE tags:sku:10001
set

# 5. 查询 Zset 类型键(如价格索引)
127.0.0.1:6379> TYPE sku:price:index
zset

2.3 获取 DB 中的键列表

需先获取 DB 0 中的键,推荐使用 SCAN 命令(非阻塞,适合生产环境),替代 KEYS *(会阻塞 Redis,键多时有风险)。

用法:SCAN 游标 [MATCH 模式] [COUNT 数量]

  • 游标:初始为 0,每次执行返回新游标,直到游标为 0 表示迭代完成。
  • MATCH:可选,按模式过滤键(如 sku:* 匹配所有以 sku: 开头的键)。
  • COUNT:可选,指定每次迭代返回的键数量(非精确值,默认 10)。
示例:迭代获取 DB 0 中所有键(每次返回约 100 个):
127.0.0.1:6379> SCAN 0 COUNT 100  # 初始游标 0,每次获取约 100 个键
1) "100"  # 下一次迭代的游标(非 0 表示未完成)
2) 1) "sku:10001"
   2) "skus"
   3) "user:100"
   4) "cart:1001"
   ...  # 其他键

# 继续迭代(使用上一次返回的游标 100)
127.0.0.1:6379> SCAN 100 COUNT 100
1) "0"  # 游标为 0,迭代完成
2) 1) "order:5001"
   2) "stock:total"
   ...  # 剩余键

3. Redis String 类型操作分类详解

3.1. 基础设值与取值操作

操作类型语法示例关键字说明(操作逻辑)商超场景案例优化点时间复杂度
单键设值(覆盖式) SET sku:10001 '{"name":"牛奶","price":5.9,"stock":100}' 1. 无论键是否存在,均覆盖原有值;
2. 支持可选参数:NX(仅键不存在时设值)、XX(仅键存在时设值);EX/PX(过期时间)、KEEPTTL(保留原过期时间)
给 SKU 10001 设置基础信息(名称、价格、库存),覆盖历史数据 1. 需保留过期时间时加 KEEPTTL
2. 原子设值 + 过期用 SET key val EX 3600 替代分步操作
O(1)
单键设值(仅键不存在时) SET sku:10002 '{"name":"面包","price":3.5,"stock":50}' NX 或 SETNX sku:10002 '{"name":"面包","price":3.5,"stock":50}' 1. 原子操作,仅当键不存在时设值,存在则不执行;
2. SETNX 是 SET ... NX 的简写
新 SKU 10002 上架时初始化缓存,防止多线程重复初始化(避免库存被覆盖) 1. 结合 EX 设置过期时间(如 SET ... NX EX 86400);
2. 不依赖此命令实现分布式锁
O(1)
单键设值(仅键存在时) SET sku:10001 '{"name":"牛奶","price":6.5,"stock":90}' XX 原子操作,仅当键已存在时更新值,不存在则不执行(避免误设新键) 仅当 SKU 10001 已存在时,更新其价格(从 5.9 涨至 6.5)和库存 1. 配合 KEEPTTL 保留原过期时间;
2. 用于「更新已有数据」场景,防止初始化不存在的 SKU
O(1)
单键设值并返回旧值 GETSET sku:10001:stock 80 1. 原子操作:先获取键的旧值,再设置新值;
2. 若键不存在,返回 nil 并设新值为指定值
SKU 10001 库存重置为 80,同时获取重置前的旧库存(用于日志记录) 1. 确保键值为整数 / 字符串类型;
2. 不用于高并发更新(旧值可能已被其他线程修改)
O(1)
单键设值 + 过期时间(秒) SETEX sku:10003:promo_price 3600 4.9 或 SET sku:10003:promo_price 4.9 EX 3600 1. 原子操作:设值同时指定过期时间(秒);
2. SETEX 是专用命令,SET ... EX 更灵活(可加 NX/XX)
SKU 10003 开启 1 小时限时促销,设置促销价 4.9 元,过期后自动失效 1. 优先用 SET ... EX(支持 NX/XX);
2. 过期时间不宜过短(避免频繁重建缓存)
O(1)
单键设值 + 过期时间(毫秒) PSETEX sku:10003:verify_code 60000 "123456" 原子操作:设值同时指定过期时间(毫秒),适用于短时效场景(如验证码) 生成 SKU 10003 的验证短信,60 秒后失效 1. 毫秒级精度适合短时效场景;
2. 配合 NX 避免重复生成(PSETEX ... NX
O(1)
单键取值 GET sku:10001 或 GET sku:10001:price 1. 获取键对应的 value,键不存在返回 nil
2. 若 value 是 JSON 字符串,需业务层解析
查询 SKU 10001 的完整信息(JSON),或仅查询其价格(单独存储 price 键时) 1. 若 value 过大(如 >1MB),拆分字段为独立键;
2. 频繁查询的小值建议开启缓存预热
O(1)

如果你的操作是:更新这个 JSON 中的 price 字段为新值,并为整个 sku:10001 键设置过期时间(注意:Redis 的过期时间只能作用于「整个键」,无法单独为 JSON 内部的某个字段设置过期)

3.2. 批量操作

操作类型语法示例关键字说明(操作逻辑)商超场景案例优化点时间复杂度
批量设值 MSET sku:10004 '{"name":"可乐","price":2.5}' sku:10005 '{"name":"薯片","price":4.8}' 1. 原子操作:批量设置多个键值,覆盖已有键;
2. 若部分键存在、部分不存在,均会覆盖 / 设置
批量初始化 SKU 10004、10005 的基础信息 1. 单次批量键数量控制在 500-1000 个(避免网络包过大或阻塞);
2. 非事务场景用 MSET
O(N)
批量取值 MGET sku:10004 sku:10005 sku:10006 1. 批量获取多个键值,不存在的键返回 nil
2. 仅需 1 次网络请求,比多次 GET 高效
批量查询 SKU 10004、10005、10006 的完整信息,用于商品列表页展示 1. 控制批量数量(避免获取大量大 key);
2. 过滤返回的 nil 值(对应不存在的 SKU)
O(N)
批量设值(仅键均不存在) MSETNX sku:10006 '{"name":"饼干","price":3.2}' sku:10007 '{"name":"矿泉水","price":1.5}' 1. 原子操作:所有键均不存在时才批量设值,有一个存在则全部不执行;
2. 不支持设置过期时间
批量上架新 SKU 10006、10007,确保不会覆盖已有 SKU 缓存 1. 批量设值后需单独执行 EXPIRE(可结合事务);
2. 批量数量不宜过大(避免操作耗时)
O(N)

3.3. 数值操作(自增 / 自减)

操作类型语法示例关键字说明(操作逻辑)商超场景案例优化点时间复杂度
整数自增(+1) INCR sku:10001:sales 1. 原子操作:键值 + 1,返回自增后的值;
2. 键不存在则先设为 0 再 + 1;
3. 键值非整数则报错
SKU 10001 卖出 1 件,销量统计 + 1 1. 高并发场景用 INCR 替代「客户端读→加 1→写回」(避免竞态);
2. 需限制最大值时,业务层判断结果
O(1)
整数自增指定步长 INCRBY sku:10001:sales 5 1. 原子操作:键值 + 指定步长(step 可正可负,负步长等价于自减);
2. 键不存在则先设为 0 再计算
SKU 10001 批量卖出 5 件,销量 + 5;或退货 2 件(INCRBY sku:10001:sales -2 1. 步长为负时无需额外用 DECRBY,统一用 INCRBY 更简洁;
2. 步长不宜过大(避免值突变)
O(1)
整数自减(-1) DECR sku:10001:stock 1. 原子操作:键值 - 1,返回自减后的值;
2. 键不存在则先设为 0 再 - 1;
3. 键值非整数则报错
SKU 10001 卖出 1 件,库存 - 1 1. 库存需避免负数时,业务层判断自减后结果(如 <0 则 INCR 回滚);
2. 不依赖 Redis 原生控制库存下限
O(1)
整数自减指定步长 DECRBY sku:10001:stock 10 1. 原子操作:键值 - 指定步长(step 为正整数);
2. 键不存在则先设为 0 再计算
SKU 10001 批量出库 10 件,库存 - 10 1. 批量出库前先 GET 库存,确认足够后再 DECRBY(避免超卖);
2. 高并发下用 WATCH+ 事务确保原子性
O(1)
浮点数自增指定步长 INCRBYFLOAT sku:10001:price 0.5 或 INCRBYFLOAT sku:10001:price -0.3 1. 原子操作:键值增减浮点数步长(支持正负);
2. 键不存在则先设为 0.0 再计算;
3. 精度受浮点数限制
SKU 10001 价格微调:涨 0.5 元(5.9→6.4),或降 0.3 元(6.4→6.1) 1. 避免频繁微调(防止浮点数精度丢失);
2. 建议用分作为单位存整数(如 590 代表 5.90 元)
O(1)

3.4. 字符串操作(长度、追加、子串)

操作类型语法示例关键字说明(操作逻辑)商超场景案例优化点时间复杂度
获取字符串长度 STRLEN sku:10001 1. 返回键值的字节长度(UTF-8 下中文占 3 字节,英文占 1 字节);
2. 键不存在返回 0
检查 SKU 10001 的 JSON 信息长度,判断是否超过缓存存储上限(如限制 1024 字节) 1. 先通过 STRLEN 判断值是否为空(长度 0),再决定是否 GET 解析;
2. 中文场景注意字节长度与字符数的差异
O(1)
追加字符串 APPEND sku:10001:remark " [已补货]" 1. 将 value 追加到原键值末尾,键不存在则等同于 SET key value
2. 返回追加后的总字节长度
SKU 10001 的备注信息原本是「常温保存」,追加后变为「常温保存 [已补货]」 1. 避免频繁 APPEND 导致 value 过大(建议拆分备注为独立键);
2. 追加前确认键值格式(如 JSON 需先解析)
O(1)
截取字符串(子串) GETRANGE sku:10001:name 0 9 1. 按字节索引截取子串,start=0 为开头,end=-1 为完整字符串;
2. 键不存在返回空字符串
SKU 10001 的名称是「进口纯牛奶 200ml」(字节长度超 10),截取前 10 字节用于列表页短名称展示 1. UTF-8 多字节字符场景(如中文),直接截取可能导致乱码(需业务层先按字符分割);
2. 仅用于短字符串截取
O(1)
设置指定位置字符 SETRANGE sku:10001:status 0 '1' 1. 按字节偏移量 offset 替换字符,value 仅支持单个字符(1 字节);
2. 键不存在则先补 0 字节到 offset+1 长度再设置
SKU 10001 的状态键 sku:10001:status 原本是「0」(下架),将第 0 字节改为「1」(上架) 1. 仅支持单字节字符(如数字、英文),多字节字符需用 SET 完整覆盖;
2. offset 不宜过大(避免补 0 字节浪费内存)
O(1)

3.5. 位操作(String 底层是字节数组,支持位级操作)

操作类型语法示例关键字说明(操作逻辑)商超场景案例优化点时间复杂度
设置指定位置的位 SETBIT sku:checkin:202409 15 1 1. offset 为位索引(从 0 开始);bit 只能是 0 或 1;
2. 键不存在,先补 0 到 offset 再设置
记录 2024 年 9 月第 15 天(15 日)SKU 巡检状态:1 = 已巡检,0 = 未巡检 1. 位索引范围建议控制在 10 万以内(避免键值过大);
2. 配合日期键名(如 sku:checkin:202409)按周期管理
O(1)
获取指定位置的位 GETBIT sku:checkin:202409 15 1. 若 offset 超出字符串长度,返回 0;
2. 键不存在,返回 0
查询 2024 年 9 月 15 日 SKU 巡检状态(返回 1 表示已巡检) 1. 先通过 BITCOUNT 确认是否有位被设置,再查询具体位置;
2. 批量查询用 BITOP 合并后处理
O(1)
统计位为 1 的数量 BITCOUNT sku:checkin:202409 或 BITCOUNT sku:checkin:202409 0 1 1. 可选 start/end(字节索引),统计指定字节范围内的 1 位数;
2. 键不存在返回 0
统计 2024 年 9 月总共有多少天完成了 SKU 巡检(总位数 = 当月天数) 1. 结合 start/end 分段统计(如按周统计);
2. 大位数场景(如 100 万位)可后台异步统计
O(N)
位运算(多 key 间) BITOP OR sku:checkin:202409:total sku:checkin:202409:a sku:checkin:202409:b 1. op 支持 AND/OR/XOR/NOT(NOT 仅支持 1 个 key);
2. 结果存入 destkey
合并 A、B 两个巡检员的 9 月巡检记录(OR 运算:任一巡检员已检则记为 1) 1. 运算前确保参与 key 的位数一致(避免结果异常);
2. 大 key 位运算后用 UNLINK 清理临时 key
O(N)
查找第一个为 0/1 的位 BITPOS sku:checkin:202409 0 或 BITPOS sku:checkin:202409 1 0 2 1. 查找从 start 字节开始,第一个值为 bit(0 或 1)的位索引;
2. 键不存在,返回 0(bit=0)或 -1(bit=1)
查找 2024 年 9 月前 3 天(0-2 字节)中第一个未巡检的日期(bit=0) 1. 配合 start/end 缩小查找范围(提升效率);
2. 未找到时通过返回值区分「键不存在」和「全为目标位」
O(N)

4. Redis Hash 类型操作分类详解

4.1. 基础设值与取值操作

操作类型语法示例关键字说明(操作逻辑)商超场景案例优化点时间复杂度
设单个字段值 HSET sku:10001 name "牛奶" price 5.9 stock 100 1. 为哈希表设置一个或多个字段值,字段存在则覆盖,不存在则新增;
2. 返回成功设置的字段数量(不包含已存在字段)
给 SKU 10001 设置名称、价格、库存字段值 1. 单个字段更新用 HSET 比 HMSET 更简洁;
2. 结合 HSETNX 确保字段首次设置的原子性
O(1)
设单个字段值(仅不存在) HSETNX sku:10001 origin "本地" 1. 仅当字段不存在时设置值,存在则不执行;
2. 原子操作,返回 1(成功)或 0(失败)
为 SKU 10001 首次设置产地字段(避免覆盖已有产地信息) 1. 用于初始化必填字段,确保数据一致性;
2. 多字段初始化建议用 HMSET 配合业务层判断
O(1)
获取单个字段值 HGET sku:10001 price 1. 返回哈希表中指定字段的值,字段不存在返回 nil
2. 哈希表不存在视为空表,返回 nil
查询 SKU 10001 的价格(单独获取某个属性,避免解析完整 JSON) 1. 频繁查询的字段建议单独缓存;
2. 结合 HEXISTS 先判断字段是否存在再获取
O(1)
获取所有字段和值 HGETALL sku:10001 1. 返回哈希表中所有字段和值(字段、值交替出现的列表);
2. 哈希表不存在返回空列表
查询 SKU 10001 的完整信息(名称、价格、库存等所有属性) 1. 避免在大哈希表(>1000 字段)上使用(耗时与字段数成正比);
2. 只需要部分字段时用 HMGET
O(N)
判断字段是否存在 HEXISTS sku:10001 discount 1. 检查哈希表中是否存在指定字段,返回 1(存在)或 0(不存在);
2. 哈希表不存在返回 0
判断 SKU 10001 是否设置了折扣字段(用于促销活动逻辑) 1. 更新字段前先判断是否存在,避免误操作;
2. 批量判断用 HMGET 结合 nil 过滤
O(1)

4.2. 批量操作

操作类型语法示例关键字说明(操作逻辑)商超场景案例优化点时间复杂度
批量设字段值 HMSET sku:10002 name "面包" price 3.5 stock 50 origin "外地" 1. 批量设置多个字段值,原子操作(要么全成功,要么全失败);
2. 字段存在则覆盖,不存在则新增
批量初始化 SKU 10002 的名称、价格、库存、产地等属性 1. 单次批量字段数控制在 500 以内(避免网络包过大);
2. Redis 4.0+ 中 HMSET 已被 HSET 替代(HSET 支持多字段)
O(N)
批量获取字段值 HMGET sku:10002 name price stock 1. 批量获取多个字段值,返回与字段顺序对应的列表(不存在的字段返回 nil);
2. 哈希表不存在返回全 nil 列表
批量查询 SKU 10002 的名称、价格、库存(商品列表页展示所需字段) 1. 只获取必要字段,减少数据传输量;
2. 结合业务场景排序字段顺序,便于解析
O(N)
获取所有字段名 HKEYS sku:10003 1. 返回哈希表中所有字段名的列表;
2. 哈希表不存在返回空列表
获取 SKU 10003 的所有属性名称(用于动态展示商品信息) 1. 大哈希表避免使用(字段过多时耗时);
2. 配合 HLEN 先判断字段数量再获取
O(N)
获取所有字段值 HVALS sku:10003 1. 返回哈希表中所有字段值的列表;
2. 哈希表不存在返回空列表
获取 SKU 10003 的所有属性值(用于数据备份或同步) 1. 同 HKEYS,避免在大哈希表上使用;
2. 敏感字段建议单独处理,不通过 HVALS 暴露
O(N)

4.3. 字段操作(删除、长度、数值增减)

操作类型语法示例关键字说明(操作逻辑)商超场景案例优化点时间复杂度
删除字段 HDEL sku:10001 origin 或 HDEL sku:10001 discount promotion 1. 删除哈希表中一个或多个字段,返回成功删除的字段数量;
2. 字段不存在或哈希表不存在返回 0
移除 SKU 10001 的产地字段,或批量删除过期的折扣、促销字段 1. 批量删除字段数控制在 1000 以内;
2. 不再使用的大哈希表建议直接 DEL 键,而非逐个删字段
O(N)
获取字段数量 HLEN sku:10001 1. 返回哈希表中字段的数量;
2. 哈希表不存在返回 0
统计 SKU 10001 的属性数量(用于校验数据完整性) 1. 结合 HKEYS 使用,先通过 HLEN 判断是否有字段再获取;
2. 监控字段数量异常增长(可能是数据错误)
O(1)
整数字段自增 HINCRBY sku:10001 sales 1 或 HINCRBY sku:10001 stock -1 1. 原子操作:为整数字段增减指定步长(步长可正可负);
2. 字段不存在则先设为 0 再计算;
3. 字段值非整数则报错
SKU 10001 销量 + 1(卖出 1 件),或库存 - 1(出库 1 件) 1. 高并发场景用 HINCRBY 替代「查→改→写」(避免竞态);
2. 库存需防负时,业务层判断结果
O(1)
浮点数字段自增 HINCRBYFLOAT sku:10001 price 0.5 或 HINCRBYFLOAT sku:10001 price -0.3 1. 原子操作:为浮点数字段增减指定步长(支持正负);
2. 字段不存在则先设为 0.0 再计算;
3. 精度受浮点数限制
SKU 10001 价格微调:涨 0.5 元(5.9→6.4),或降 0.3 元(6.4→6.1) 1. 同 String 类型,建议用分作为单位存整数(避免精度问题);
2. 步长不宜过大(防止价格突变)
O(1)

4.4. 其他操作(迭代、设置过期)

操作类型语法示例关键字说明(操作逻辑)商超场景案例优化点时间复杂度
迭代字段(游标式) HSCAN sku:10004 0 COUNT 10 1. 游标式迭代哈希表字段(类似 SCAN),避免 HKEYS/HVALS 的阻塞问题;
2. 返回新游标和字段 - 值对列表
分页获取 SKU 10004 的属性(适用于字段较多的商品) 1. COUNT 参数建议设为 100-1000(平衡性能和次数);
2. 迭代完成后需处理游标为 0 的情况
O (1) 单次(整体取决于字段数)
设置哈希表过期时间 EXPIRE sku:10005 86400 或 PEXPIRE sku:10005 86400000 1. 为哈希表设置过期时间(秒 / 毫秒),过期后自动删除整个键;
2. 哈希表不存在返回 0
为临时上架的 SKU 10005 设置 24 小时过期时间(自动下架) 1. 过期时间作用于整个哈希表,无法单独为字段设过期;
2. 结合 TTL 监控剩余有效期
O(1)
重命名哈希表 RENAME sku:10005 sku:10005:old 1. 重命名哈希表的键名,若目标键存在则覆盖;
2. 原键不存在返回错误
将下架的 SKU 10005 重命名为 sku:10005:old(标记为历史数据) 1. 重命名期间原键会被阻塞(短时间),避免在高并发访问的哈希表上使用;
2. 先 EXISTS 检查目标键是否存在
O(1)

4.5. 关键说明

    1. Hash 类型优势:适合存储对象型数据(如商品信息),相比多个 String 键更节省内存,且便于批量操作。
    2. 性能注意:
      • 单个哈希表字段数建议控制在 1000 以内(超过后哈希表编码会从 ziplist 转为 hashtable,内存占用增加)。
      • 避免在大哈希表上使用 HGETALL/HKEYS/HVALS,改用 HSCAN 分页迭代。
    3. 商超场景核心用法:
      • 商品基础信息(名称、价格、库存等)用 Hash 存储,便于整体管理。
      • 高频更新的字段(库存、销量)用 HINCRBY 确保原子性。
      • 临时商品信息结合 EXPIRE 自动清理,减少手动维护成本。

5. Redis List 类型操作详解

以下是 Redis List 类型的操作分类列表,按照操作类型进行了系统性的整理:

5.1. 元素添加操作

 
操作类型语法示例关键字说明(操作逻辑)商超场景案例优化点时间复杂度是否阻塞
左端推入 LPUSH orders uid:1001 将一个或多个值插入到列表头部 新订单加入处理队列头部,优先处理 批量操作时使用 LPUSH key elem1 elem2 elem3 O(1) 每个元素
右端推入 RPUSH orders uid:1002 将一个或多个值插入到列表尾部 新订单加入处理队列尾部,排队处理 同上,使用批量操作减少网络往返 O(1) 每个元素
插入元素 LINSERT orders BEFORE "uid:1002" "uid:1005" 在指定元素前/后插入新元素 高优先级订单插入到普通订单前面 需要遍历列表,性能较差 O(N)

5.2. 元素移除操作

操作类型语法示例关键字说明(操作逻辑)商超场景案例优化点时间复杂度是否阻塞
左端弹出 LPOP orders 移除并返回列表头部元素 从订单队列头部取出订单处理 处理 nil 结果,避免空轮询 O(1)
右端弹出 RPOP orders 移除并返回列表尾部元素 从订单队列尾部取出订单处理 同上 O(1)
指定移除 LREM orders 2 "uid:1001" 移除列表中与指定值相等的元素 用户取消订单,从队列中移除 需要遍历列表,性能与列表长度成正比 O(N)
修剪列表 LTRIM recent_orders 0 99 只保留指定区间内的元素 只保留最近100条订单记录 控制列表长度,防止内存无限增长 O(N)

5.3. 阻塞操作

操作类型语法示例关键字说明(操作逻辑)商超场景案例优化点时间复杂度是否阻塞
阻塞左端弹出 BLPOP order_queue 30 列表为空时阻塞连接,直到超时或有元素 订单处理worker等待新订单 设置合理超时时间,避免无限阻塞 O(1)
阻塞右端弹出 BRPOP order_queue 30 同上,但从右端弹出 同上 同上 O(1)
阻塞弹出并推入 BRPOPLPUSH src_queue dst_queue 30 从源列表弹出元素并推入目标列表,阻塞版本 处理订单后将其移动到已处理队列 原子操作,保证数据不丢失 O(1)

5.4. 查询操作

操作类型语法示例关键字说明(操作逻辑)商超场景案例优化点时间复杂度是否阻塞
获取范围 LRANGE orders 0 4 返回列表中指定区间内的元素 查看接下来要处理的5个订单 避免获取整个大列表 O(S+N)
获取指定索引元素 LINDEX orders 0 通过索引获取列表中的元素 查看队列中最优先的订单 需要遍历列表,性能较差 O(N)
获取列表长度 LLEN orders 返回列表的长度 查看当前待处理订单数量  1. 高效查询:该命令时间复杂度为 O(1),可以高频调用而无性能压力。
2. 业务逻辑处理:客户端需处理返回值为 0 的情况(即队列为空或Key不存在)。
O(1)

5.5. 高级操作

操作类型语法示例关键字说明(操作逻辑)商超场景案例优化点时间复杂度是否阻塞
弹出并推入 RPOPLPUSH src_queue dst_queue 原子性地从源列表尾部弹出元素并推入目标列表头部 处理完订单后移动到已完成队列 原子操作,保证数据一致性 O(1)
设置指定索引值 LSET orders 0 "uid:1005" 通过索引设置列表元素的值 修改队列中某个订单的优先级 需要确保索引不超过列表长度 O(N)

5.6. List 类型应用模式总结

  1. 栈(Stack)结构:

    • 后进先出(LIFO): LPUSH + LPOP 或 RPUSH + RPOP

  2. 队列(Queue)结构:

    • 先进先出(FIFO): LPUSH + RPOP 或 RPUSH + LPOP

    • 阻塞队列: LPUSH + BRPOP (最常用)

  3. 有限集合(Capped Collection):

    • LPUSH + LTRIM 实现固定长度的列表,如最新N条记录

  4. 消息队列:

    • 使用阻塞操作(BLPOP/BRPOP)实现高效的消息传递

    • 使用RPOPLPUSH实现安全队列(处理中的消息移到另一列表)

  5. 循环列表:

    • RPOPLPUSH同一列表可实现循环列表效果

Redis List 的阻塞操作是其独特优势,特别适合实现消息队列、任务队列等场景,能够有效避免客户端的无效轮询,提升系统效率。

6. Redis Set 类型操作详解

Set 是 Redis 中的无序集合,它包含不重复的字符串元素。Set 提供了高效的成员检查、交集、并集、差集等操作,非常适合需要处理唯一性数据的场景。

以下是 Redis Set 类型的操作分类列表:

6.1. 元素添加操作

操作类型语法示例关键字说明(操作逻辑)商超场景案例优化点时间复杂度是否阻塞
添加元素 SADD daily:visitors "user:123" 向集合添加一个或多个成员 记录每日到店访客ID 批量添加时使用 SADD key member1 member2 O(1) 每个元素
移动元素 SMOVE source_set target_set "member" 将元素从源集合移动到目标集合 将VIP客户从普通客户集移动到VIP客户集 原子操作,保证数据一致性 O(1)

6.2. 元素移除操作

操作类型语法示例关键字说明(操作逻辑)商超场景案例优化点时间复杂度是否阻塞
移除元素 SREM daily:visitors "user:123" 移除集合中一个或多个成员 从访客记录中移除无效用户 批量移除时使用 SREM key member1 member2 O(1) 每个元素
随机弹出 SPOP products:viewed:user456 随机移除并返回集合中的一个元素 从用户浏览历史中随机移除一条记录 可指定弹出数量 SPOP key count O(1)

6.3. 查询操作

操作类型语法示例关键字说明(操作逻辑)商超场景案例优化点时间复杂度是否阻塞
获取所有成员 SMEMBERS vip:customers 返回集合中的所有成员 获取所有VIP客户列表 慎用大集合,可能阻塞Redis O(N) 否(但可能影响性能)
随机获取元素 SRANDMEMBER daily:visitors 随机返回集合中一个或多个元素 随机抽取一名幸运访客 可指定返回数量 SRANDMEMBER key count O(1)
检查成员存在 SISMEMBER vip:customers "user:789" 判断元素是否是集合的成员 检查用户是否是VIP客户 O(1)
获取集合大小 SCARD daily:visitors 获取集合的成员数 统计每日访客数量 O(1)

6.4. 集合运算操作

操作类型语法示例关键字说明(操作逻辑)商超场景案例优化点时间复杂度是否阻塞
交集 SINTER set1 set2 返回所有给定集合的交集 找出既是老客户又是VIP客户的用户 对多个集合求交时复杂度较高 O(N*M)
交集存储 SINTERSTORE result_set set1 set2 将交集结果存储到新集合 创建"老客户且是VIP"的新集合 避免传输大量结果数据 O(N*M)
并集 SUNION set1 set2 返回所有给定集合的并集 合并本周和上周的所有访客 对多个集合求并时复杂度较高 O(N)
并集存储 SUNIONSTORE result_set set1 set2 将并集结果存储到新集合 创建"两周所有访客"的新集合 避免传输大量结果数据 O(N)
差集 SDIFF set1 set2 返回第一个集合与其他集合的差集 找出本周新增的访客(本周-上周) 对多个集合求差时复杂度较高 O(N)
差集存储 SDIFFSTORE result_set set1 set2 将差集结果存储到新集合 创建"本周新增访客"集合 避免传输大量结果数据 O(N)

6.5. 迭代操作

操作类型语法示例关键字说明(操作逻辑)商超场景案例优化点时间复杂度是否阻塞
迭代集合 SSCAN vip:customers 0 MATCH "user:*" COUNT 100 增量迭代集合中的元素 分批处理VIP客户数据 替代SMEMBERS处理大集合 每次调用O(1)

6.6 Set 类型应用模式总结

  1. 唯一性数据存储:

    • 用户标签、用户权限、IP黑名单等需要保证唯一性的数据

  2. 关系表示:

    • 用户-商品收藏关系、用户-用户关注关系等

  3. 随机抽取:

    • 抽奖系统、随机推荐等场景

  4. 数据过滤与统计:

    • 使用集合运算进行数据筛选和统计分析

  5. 共同特征查找:

    • 查找具有共同特征的用户或物品

Set 类型的优势在于其O(1)时间复杂度的添加、删除和查找操作,以及强大的集合运算能力。但需要注意,对于非常大的集合,SMEMBERS命令可能会消耗大量内存和网络资源,此时应使用SSCAN命令进行增量迭代。

Set 类型的所有操作都是非阻塞的,但集合运算操作(如SINTERSUNION等)在处理大型集合时可能会消耗较多CPU资源,影响Redis的响应性能。

7. Redis Sorted Set 类型操作详解

Sorted Set(有序集合)是 Redis 中一个非常强大的数据结构,它类似于 Set,但每个成员都关联一个分数(score),使得成员可以按照分数进行排序。Sorted Set 同时具有集合的唯一性和有序性特点。

以下是 Redis Sorted Set 类型的操作分类列表:

7.1. 元素添加/更新操作

操作类型语法示例关键字说明(操作逻辑)商超场景案例优化点时间复杂度是否阻塞
添加元素 ZADD product:ranking 1520 "product:1001" 向有序集合添加一个或多个成员,或更新已存在成员的分数 记录商品热度分数 批量添加时使用 ZADD key score1 member1 score2 member2 O(log N) 每个元素
增量更新 ZINCRBY product:ranking 50 "product:1001" 增加成员的分数 增加商品的点击热度 原子操作,避免先ZSCORE再ZADD O(log N)

7.2. 元素移除操作

操作类型语法示例关键字说明(操作逻辑)商超场景案例优化点时间复杂度是否阻塞
移除元素 ZREM product:ranking "product:1001" 移除有序集合中的一个或多个成员 下架商品,从排行榜移除 批量移除时使用 ZREM key member1 member2 O(M*log N) M为成员数
按排名移除 ZREMRANGEBYRANK product:ranking 0 4 移除指定排名区间内的所有成员 清空排行榜前5名 谨慎使用,会删除多个元素 O(log N + M)
按分数移除 ZREMRANGEBYSCORE product:ranking 0 100 移除指定分数区间内的所有成员 移除热度低于100的商品 同上,注意影响范围 O(log N + M)

7.3. 查询操作

操作类型语法示例关键字说明(操作逻辑)商超场景案例优化点时间复杂度是否阻塞
获取分数 ZSCORE product:ranking "product:1001" 返回成员的分数值 查询某个商品的当前热度 O(1)
获取排名 ZRANK product:ranking "product:1001" 返回成员在有序集合中的排名(升序) 查询商品在排行榜中的位置 O(log N)
获取逆序排名 ZREVRANK product:ranking "product:1001" 返回成员在有序集合中的排名(降序) 查询商品在排行榜中的位置(从高到低) O(log N)
获取集合大小 ZCARD product:ranking 获取有序集合的成员数量 统计排行榜中商品总数 O(1)
统计分数区间 ZCOUNT product:ranking 100 500 计算指定分数范围内的成员数量 统计热度在100-500之间的商品数量 O(log N)

7.4. 范围查询操作

操作类型语法示例关键字说明(操作逻辑)商超场景案例优化点时间复杂度是否阻塞
按排名范围查询 ZRANGE product:ranking 0 9 WITHSCORES 通过索引区间返回有序集合成员(升序) 获取排行榜前10名商品 使用WITHSCORES同时返回分数 O(log N + M)
按排名范围逆序查询 ZREVRANGE product:ranking 0 9 WITHSCORES 通过索引区间返回有序集合成员(降序) 获取排行榜前10名商品(从高到低) 同上 O(log N + M)
按分数范围查询 ZRANGEBYSCORE product:ranking 100 500 WITHSCORES 通过分数返回有序集合成员 获取热度在100-500之间的所有商品 可结合LIMIT分页 O(log N + M)
按分数范围逆序查询 ZREVRANGEBYSCORE product:ranking 500 100 WITHSCORES 通过分数返回有序集合成员(降序) 获取热度在100-500之间的所有商品(从高到低) 同上 O(log N + M)

7.5. 集合运算操作

操作类型语法示例关键字说明(操作逻辑)商超场景案例优化点时间复杂度是否阻塞
交集存储 ZINTERSTORE result 2 set1 set2 WEIGHTS 2 3 计算多个有序集合的交集并存储结果 合并多个商品排行榜 可以设置权重和聚合方法 O(NK)+O(Mlog M)
并集存储 ZUNIONSTORE result 2 set1 set2 WEIGHTS 2 3 计算多个有序集合的并集并存储结果 合并多个商品排行榜 同上 O(N)+O(M*log M)

7.6. 弹出操作

操作类型语法示例关键字说明(操作逻辑)商超场景案例优化点时间复杂度是否阻塞
弹出最高分 ZPOPMAX product:ranking 5 移除并返回分数最高的成员 获取并移除热度最高的5个商品 Redis 5.0+ 支持 O(log N * M)
弹出最低分 ZPOPMIN product:ranking 5 移除并返回分数最低的成员 获取并移除热度最低的5个商品 Redis 5.0+ 支持 O(log N * M)
阻塞弹出最高分 BZPOPMAX queues 30 阻塞式弹出最高分成员 从多个优先级队列中获取最高优先级任务 Redis 5.0+ 支持 O(log N)
阻塞弹出最低分 BZPOPMIN queues 30 阻塞式弹出最低分成员 从多个优先级队列中获取最低优先级任务 Redis 5.0+ 支持 O(log N)

7.7. 迭代操作

操作类型语法示例关键字说明(操作逻辑)商超场景案例优化点时间复杂度是否阻塞
迭代集合 ZSCAN product:ranking 0 MATCH "product:1*" COUNT 100 增量迭代有序集合中的元素 分批处理特定类型的商品数据 替代ZRANGE处理大集合 每次调用O(1)

7.8 Sorted Set 类型应用模式总结

  1. 排行榜系统:

    • 商品热度榜、用户积分榜、销售排行榜等

  2. 优先级队列:

    • 任务调度系统,按优先级处理任务

  3. 范围查询:

    • 按分数范围查询数据,如查询价格在某个区间的商品

  4. 时间轴数据:

    • 使用时间戳作为分数,存储按时间排序的数据

  5. 带权重的集合运算:

    • 复杂的排行榜合并和计算

Sorted Set 类型的优势在于其既能保证元素的唯一性,又能按照分数进行排序,同时提供了丰富的范围查询和集合运算功能。需要注意,ZRANGE、ZINTERSTORE等范围操作在处理大量数据时可能会消耗较多资源,应根据实际情况合理使用。

Sorted Set 的阻塞操作(BZPOPMAX/BZPOPMIN)主要用于实现优先级队列的消费者模式,能够在队列为空时阻塞等待,避免无效轮询。

8. Redis Bitmap 类型操作详解

Bitmap(位图)不是独立的数据类型,而是基于 String 类型的一套位操作命令。Bitmap 通过将字符串视为位数组,提供了极其高效的空间利用率和位操作能力,特别适合布尔值统计和标记场景。

以下是 Redis Bitmap 类型的操作分类列表:

8.1. 位设置/清除操作

操作类型语法示例关键字说明(操作逻辑)商超场景案例优化点时间复杂度是否阻塞
设置位值 SETBIT user:sign:202409 15 1 对 key 所储存的字符串值,设置或清除指定偏移量上的位(bit) 记录用户ID为15的用户在2024年9月某天签到 偏移量从0开始,最大2³² O(1)
清除位值 SETBIT user:sign:202409 15 0 清除指定偏移量上的位(设置为0) 取消用户的签到记录 实际上是SETBIT的值为0 O(1)

8.2. 位查询操作

操作类型语法示例关键字说明(操作逻辑)商超场景案例优化点时间复杂度是否阻塞
获取位值 GETBIT user:sign:202409 15 对 key 所储存的字符串值,获取指定偏移量上的位(bit) 查询用户ID为15的用户在2024年9月某天是否签到 O(1)
获取位图 GET user:sign:202409 获取整个位图的二进制数据 导出某天的所有签到数据 可能返回大量数据,慎用 O(1)

8.3. 位统计操作

操作类型语法示例关键字说明(操作逻辑)商超场景案例优化点时间复杂度是否阻塞
统计置位数 BITCOUNT user:sign:202409 计算给定字符串中,被设置为 1 的比特位的数量 统计某天签到的总用户数 可指定范围 BITCOUNT key start end O(N)
按位统计 BITCOUNT user:sign:202409 0 2 计算指定字节范围内的置位数 统计前3个字节范围内的签到用户数 使用字节偏移而非位偏移 O(N)

8.4. 位图运算操作

操作类型语法示例关键字说明(操作逻辑)商超场景案例优化点时间复杂度是否阻塞
位与运算 BITOP AND result user:sign:0901 user:sign:0902 对一个或多个位图执行逻辑与操作,结果存到新位图 找出9月1日和2日都签到的用户 支持AND/OR/XOR/NOT操作 O(N) 是(大数据量时)
位或运算 BITOP OR result user:sign:0901 user:sign:0902 对一个或多个位图执行逻辑或操作 找出9月1日或2日签到的所有用户 同上 O(N)
位异或运算 BITOP XOR result user:sign:0901 user:sign:0902 对一个或多个位图执行逻辑异或操作 找出只在9月1日或只在9月2日签到的用户 同上 O(N)
位非运算 BITOP NOT result user:sign:0901 对位图执行逻辑非操作 找出9月1日未签到的所有用户 同上 O(N)

8.5. 位查找操作

操作类型语法示例关键字说明(操作逻辑)商超场景案例优化点时间复杂度是否阻塞
查找第一个置位 BITPOS user:sign:202409 1 返回位图中第一个值为指定bit的二进制位的位置 找到第一个签到的用户ID 可指定查找范围 BITPOS key bit start end O(N)
查找第一个清零位 BITPOS user:sign:202409 0 返回位图中第一个值为0的二进制位的位置 找到第一个未签到的用户ID 同上 O(N)

8.6. 字段位操作(Redis 7.0+)

操作类型语法示例关键字说明(操作逻辑)商超场景案例优化点时间复杂度是否阻塞
字段位操作 BITFIELD user:flags GET u4 0 对位图进行多个操作,支持整数子字段 从位图中提取用户标志位的特定字段 强大但复杂,需理解子字段概念 O(1) 每个子操作
字段位设置 BITFIELD user:flags SET u4 0 5 设置位图中特定字段的值 设置用户的权限标志位 可执行多个操作原子性 O(1) 每个子操作
原子增量 BITFIELD user:counters INCRBY u8 0 1 对位图中的整数字段进行原子增量 统计用户访问次数(8位计数器) 避免竞态条件 O(1) 每个子操作

8.8 Bitmap 类型应用模式总结

  1. 用户签到系统:

    • 使用 SETBIT/GETBIT 记录和查询每日签到

    • 使用 BITCOUNT 统计月度签到次数

  2. 活跃用户统计:

    • 使用位图记录每日活跃用户

    • 使用 BITOP 计算周/月活跃用户(OR操作)

    • 使用 BITOP 计算连续活跃用户(AND操作)

  3. 布隆过滤器:

    • 使用多个位图和哈希函数实现概率型数据结构

  4. 特征标志存储:

    • 使用 BITFIELD 紧凑存储多个布尔或枚举型特征

  5. 实时数据统计:

    • 使用位图进行各种集合运算和统计

8.9 重要注意事项

  1. 内存效率: Bitmap 极其节省内存,10,000,000 用户签到仅需约 1.2MB 内存

  2. 偏移量限制: 最大偏移量为 2³²(约42亿),足够大多数场景使用

  3. 阻塞风险: BITOP 操作在大位图时可能阻塞Redis,应在低峰期执行

  4. BITFIELD复杂性: BITFIELD 功能强大但学习曲线较陡,需仔细理解数据类型和偏移量

Bitmap 通过极致的空间效率和高效的位操作,为大规模布尔值存储和统计提供了完美的解决方案,特别适合用户行为分析、实时统计等场景。

9. Redis HyperLogLog 类型操作详解

HyperLogLog 是 Redis 中用于基数统计(估算集合中不重复元素数量)的概率算法数据结构。它提供了一种极其节省内存的方式来计算大规模数据的唯一值数量,标准误差约为 0.81%。

以下是 Redis HyperLogLog 类型的操作分类列表:

9.1. 基数添加操作

操作类型语法示例关键字说明(操作逻辑)商超场景案例优化点时间复杂度是否阻塞
添加元素 PFADD daily:uv "user:123" 将任意数量的元素添加到 HyperLogLog 中 记录每日独立访客 批量添加元素比多次调用更高效 O(1) 每个元素
批量添加 PFADD daily:uv "user:123" "user:456" "user:789" 一次性添加多个元素到 HyperLogLog 批量记录多个用户的访问 减少网络往返次数 O(N) N为元素数量

9.2. 基数统计操作

操作类型语法示例关键字说明(操作逻辑)商超场景案例优化点时间复杂度是否阻塞
基数估算 PFCOUNT daily:uv 返回给定 HyperLogLog 的基数估算值 统计今日独立访客数量 单个key的PFCOUNT非常快 O(1)
多键统计 PFCOUNT day1:uv day2:uv day3:uv 返回多个 HyperLogLog 的合并基数估算值 统计三天内的总独立访客(去重) 内部会执行合并操作 O(N) N为key数量

9.3. 数据合并操作

操作类型语法示例关键字说明(操作逻辑)商超场景案例优化点时间复杂度是否阻塞
合并存储 PFMERGE weekly:uv mon:uv tue:uv wed:uv 将多个 HyperLogLog 合并为一个新的 HyperLogLog 将一周七天的UV数据合并为周UV数据 合并后的新HLL可以继续用于统计 O(N) N为合并的key数量

9.4. 内存优化特性

操作类型语法示例关键字说明(操作逻辑)商超场景案例优化点时间复杂度是否阻塞
内存使用 (无需命令) 每个 HyperLogLog 仅占用约 12KB 内存 统计亿级用户访问仅需12KB内存 固定内存占用,与元素数量无关 - -

9.5 HyperLogLog 类型应用模式总结

  1. 大规模基数统计:

    • 网站独立访客(UV)统计

    • 搜索关键词唯一用户数统计

    • 广告点击独立用户数统计

  2. 多维度数据合并:

    • 按时间维度合并统计数据(日→周→月)

    • 按业务维度合并统计数据(不同频道的UV合并)

  3. 实时流量监控:

    • 实时统计不同页面的访问用户数

    • 监控API调用的独立用户数

9.6 HyperLogLog 的重要特性

  1. 固定内存占用: 每个 HyperLogLog 只需要约 12KB 内存,无论统计多少元素

  2. 近似计数: 提供概率性估算而非精确计数,标准误差为 0.81%

  3. 支持合并: 多个 HyperLogLog 可以被合并,合并后的基数估算仍然是准确的

  4. 非阻塞操作: 所有 HyperLogLog 操作都是非阻塞的,适合高性能场景

9.7 使用限制和注意事项

  1. 不存储原始数据: HyperLogLog 只存储基数估算信息,无法获取具体的元素内容

  2. 计数为估算值: 适用于需要大致数量而非精确值的场景

  3. 适合大规模数据: 对于小规模数据集,使用 Set 可能更合适(可获取具体元素)

  4. 合并成本: 合并多个 HyperLogLog 时有一定的计算开销,但仍在可控范围内

9.8 商超场景综合案例

bash
# 记录每日独立访客
PFADD 2024-09-08:uv "user:1001" "user:1002" "user:1003"

# 记录每周独立访客(通过合并每日数据)
PFMERGE 2024-09-week:uv 2024-09-01:uv 2024-09-02:uv ... 2024-09-07:uv

# 统计本月独立访客总数
PFCOUNT 2024-09-01:uv 2024-09-02:uv ... 2024-09-30:uv

# 比较不同商品页面的独立访客
PFCOUNT product:1001:uv product:1002:uv product:1003:uv

HyperLogLog 是 Redis 中解决大规模基数统计问题的利器,它以极小的内存开销和可接受的误差率,为亿级数据的唯一值统计提供了完美的解决方案。

 posted on 2025-07-31 17:46  xibuhaohao  阅读(7)  评论(0)    收藏  举报