This repository has been archived on 2026-05-24. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
all-in-kingsoft/hhs/Redis/03-基本命令速查.md
T
2026-05-17 00:06:11 +08:00

305 lines
13 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
tags: [Redis, 缓存, 命令]
create time: 2026-05-15 18:12
---
# Redis 基本命令速查
## 概述
按使用频率排序的常用命令,标注时间复杂度、典型场景和避坑点。完整命令参考官方文档。
### 数据类型选型速查
遇到业务需求时,按以下流程选择合适的 Redis 数据结构:
```mermaid
flowchart TD
A["需要存什么?"] --> B{"单值 / 键值对?"}
B -- 是 --> C["String<br/>缓存, 计数器, 分布式锁"]
B -- 否 --> D{"多个字段 / 对象?"}
D -- 是 --> E["Hash<br/>用户信息, 配置, 表单数据"]
D -- 否 --> F{"需要排序 / 排名?"}
F -- 是 --> G["ZSet<br/>排行榜, 延迟队列, 范围查询"]
F -- 否 --> H{"需要去重 / 集合运算?"}
H -- 是 --> I["Set<br/>标签, 共同关注, UV 统计"]
H -- 否 --> J{"需要队列 / 栈?"}
J -- 是 --> K["List<br/>消息队列, 最新列表, 栈"]
J -- 否 --> L["Pub/Sub<br/>广播, 实时通知"]
```
## String — 字符串操作
| 命令 | 返回值 | 复杂度 | 说明 |
|------|--------|--------|------|
| `SET key value [EX s] [PX ms] [NX\|XX]` | OK / nil | O(1) | **万能设置**,EX/PX 设过期,NX 仅不存在时写,XX 仅存在时写 |
| `GET key` | value / nil | O(1) | 获取值 |
| `MGET key [key...]` | values array | O(N) | 批量获取 |
| `SETRANGE key offset value` | length | O(1)* | 覆盖指定偏移量字节(*近似) |
| `APPEND key value` | new-length | O(1)* | 追加到末尾 |
| `INCR key` | incremented val | O(1) | 原子 +1 |
| `INCRBY key increment` | incremented val | O(1) | 原子 +N |
| `DECRBY key decrement` | decremented val | O(1) | 原子 -N |
| `STRLEN key` | length | O(1) | 获取字符串长度 |
| `GETSET key value` | old value | O(1) | **已废弃**,用 `SET key value NX` 替代 |
| `GETRANGE key start end` | substring | O(N) | 截取子串(end 为 -1 表示末尾) |
| `SETEX key seconds value` | OK | O(1) | **已废弃**,用 `SET key value EX seconds` 替代 |
| `PSETEX key milliseconds value` | OK | O(1) | **已废弃**,用 `SET key value PX milliseconds` 替代 |
| `MSET key value [key value ...]` | OK | O(N) | 原子设置多个键 |
```go
// SET 条件写入——分布式锁的核心
rdb.Set(ctx, "lock:order:"+orderId, "1", 3*time.Second, redis.KeepTTL|redis.OnlyIfAbsent)
// INCR 做限流计数器
rdb.IncrBy(ctx, "rate:user:"+userID, 1)
```
> [!WARNING] MGET ≠ 事务保证
> MGET 是并发执行 N 次 GET,不保证原子性。需要原子读多个字段请用 `MULTI` 或 Lua 脚本。
## Hash — 哈希操作
| 命令 | 返回值 | 复杂度 | 说明 |
|------|--------|--------|------|
| `HSET key field value [field value ...]` | added / changed count | O(N) | 设置一个或多个字段 |
| `HGET key field` | value / nil | O(1) | 获取单个字段 |
| `HMGET key field [field ...]` | values array | O(N) | 批量获取多个字段 |
| `HGETALL key` | all fields | O(N) | 获取全部键值对 ⚠️ 大 hash 慎用 |
| `HDEL key field [field ...]` | deleted count | O(N) | 删除字段 |
| `HEXISTS key field` | 1 or 0 | O(1) | 判断字段是否存在 |
| `HINCRBY key field increment` | new value | O(1) | 原子递增字段值 |
| `HSCAN key cursor MATCH pattern COUNT n` | cursor, entries | O(N) | 安全遍历,不用 HKEYS/HVALS 全量扫 |
```go
// 用户信息缓存——部分更新
pipe := rdb.Pipeline()
pipe.HSet(ctx, "user:42", "email", "new@email.com")
pipe.HSet(ctx, "user:42", "phone", "1380000")
pipe.Exec(ctx) // 管道内原子执行
```
> [!TIP] HGETALL vs HSCAN
> `HGETALL` 一步到位获取全部字段,但大 hash(>10K 字段)会阻塞主线程。生产环境推荐 `HSCAN` 分片读取。
## List — 列表操作
| 命令 | 返回值 | 复杂度 | 说明 |
|------|--------|--------|------|
| `LPUSH key elem [elem ...]` | list length | O(N) | 从左侧推入 |
| `RPUSH key elem [elem ...]` | list length | O(N) | 从右侧推入 |
| `LPOP key` | element / nil | O(1) | 弹出左侧元素 |
| `RPOP key` | element / nil | O(1) | 弹出右侧元素 |
| `LRANGE key start stop` | subarray | O(S+N) | 范围查询 S=start, N=stop-start |
| `LLEN key` | length | O(1) | 列表长度 |
| `LINDEX key index` | element | O(N) | 按索引获取 |
| `LTRIM key start stop` | OK | O(N) | 只保留指定范围(固定队列长度必备) |
| `BLPOP key [key ...] timeout` | element / nil | O(timeout) | **阻塞式** LPOP |
| `BRPOP key [key ...] timeout` | element / nil | O(timeout) | **阻塞式** RPOP |
| `RPOPLPUSH src dst` | element | O(1) | **已废弃**,用 LMOVE 替代 |
| `LMOVE key where1 where2` | element | O(1) | 弹出一端、push 到另一端(支持 LEFT/RIGHT) |
```go
// BRPOP 消费者模型
val, err := rdb.BRPop(ctx, 5*time.Second, "task_queue").Result()
if err == redis.Nil {
return nil // 超时,无消息
}
```
> [!QUESTION] LPUSH + RPOP 还是 RPUSH + LPOP?
> 两者性能相同(都是两端操作)。选择取决于语义——"先到的先处理"用 LPUSH+RPOP(FIFO),反之则相反。
## Set — 集合操作
| 命令 | 返回值 | 复杂度 | 说明 |
|------|--------|--------|------|
| `SADD key member [member ...]` | added count | O(N) | 添加成员 |
| `SREM key member [member ...]` | removed count | O(N) | 移除成员 |
| `SMEMBERS key` | all members | O(N) | 获取全部 ⚠️ |
| `SISMEMBER key member` | 1 or 0 | O(1) | 判断成员 |
| `SCARD key` | cardinality | O(1) | 元素个数 |
| `SRANDMEMBER key [count]` | member(s) | O(N) | 随机取(不删除) |
| `SPOP key [count]` | member(s) | O(N) | 随机取并删除 |
| `SINTER key [key ...]` | intersection | O(N*M) | 交集 ⚠️ 跨节点成本高 |
| `SUNION key [key ...]` | union | O(N*M) | 并集 |
| `SDIFF key [key ...]` | difference | O(N*M) | 差集 |
| `SINTERSTORE dst key [key ...]` | result count | O(N*M) | 交集结果存入新 key |
```go
// 共同关注——用户 A 和用户 B 都关注的人
common := rdb.SInter(ctx, "follow:userA", "follow:userB").Val()
// 抽奖系统——随机取 N 个不重复中奖者
winners := rdb.SPopN(ctx, "entry:lottery", 5).Val()
```
> [!TIP] Set 的典型应用场景
> - **去重**:UV 统计(`SADD` + `SCARD`)
> - **交集/并集**:共同好友、标签聚合
> - **随机抽样**:`SPOP` / `SRANDMEMBER` 做抽奖或推荐
## ZSet —— 有序集合
| 命令 | 返回值 | 复杂度 | 说明 |
|------|--------|--------|------|
| `ZADD key score member [score member ...]` | added/changed | O(N log N) | 添加/更新 |
| `ZSCORE key member` | score / nil | O(1) | 获取分数 |
| `ZINCRBY key increment member` | new score | O(log N) | 增加分数 |
| `ZRANGE key start stop [WITHSCORES]` | members | O(log N+M) | 正序范围 |
| `ZREVRANGE key start stop [WITHSCORES]` | members | O(log N+M) | 倒序范围 |
| `ZRANGEBYSCORE key min max [WITHSCORES]` | members | O(log N+M) | 分数区间 |
| `ZRANK key member` | rank / nil | O(log N) | 升序排名 |
| `ZREVRANK key member` | reverse rank / nil | O(log N) | 降序排名 |
| `ZCARD key` | count | O(1) | 元素数 |
| `ZCOUNT key min max` | count | O(log N) | 分数范围内元素数 |
| `ZREM key member [member ...]` | removed | O(M log N) | 移除 |
| `ZREMRANGEBYRANK key start stop` | removed | O(log N+M) | 按排名删 |
| `ZREMRANGEBYSCORE key min max` | removed | O(log N+M) | 按分数删 |
| `ZMSCORE key member [member ...]` | scores | O(N) | 批量获取分数(7.0+) |
| `ZPOPMAX key [count]` | top members | O(log N+M) | 弹出最高分 |
| `ZPOPMIN key [count]` | bottom members | O(log N+M) | 弹出最低分 |
| `ZINTERSTORE dst numkeys key [numkeys...]` | cardinality | O(N×K+K log K) | 多 ZSet 求交集存新 key |
| `ZUNIONSTORE dst numkeys key [numkeys...]` | cardinality | O(N×K+K log K) | 多 ZSet 求并集存新 key |
| `ZRANDMEMBER key [count] [WITHSCORES]` | members | O(N) | 随机取(7.0+) |
| `ZRANGEBYLEX key min max [LIMIT offset count]` | members | O(log N+M) | 同分数按 member 字典序排 |
| `ZSCAN key cursor MATCH pattern COUNT n` | cursor, entries | O(N) | 安全遍历 |
```go
// 排行榜——获取 TOP 10
top10 := rdb.ZRevRangeWithScores(ctx, "leaderboard", 0, 9).Val()
for _, z := range top10 {
fmt.Printf("%s: %.1f\n", z.Member, z.Score)
}
// 分数区间查询——80~100 分的学生
students := rdb.ZRangeByScore(ctx, "score:classA", redis.ZRangeBy{
Min: "80", Max: "100",
}).Val()
```
> [!TIP] 分数边界写法
> `[` 包含、`(` 不包含。例如 `"[80"` 表示 ≥80,`"(100"` 表示 <100。`-inf` 和 `+inf` 表示无穷大。
## 通用命令
| 命令 | 返回值 | 复杂度 | 说明 |
|------|--------|--------|------|
| `DEL key [key ...]` | deleted count | O(N) | N = key 的平均大小,大 key 会阻塞 |
| `EXPIRE key seconds` | 1 or 0 | O(1) | 设过期时间(秒) |
| `PEXPIRE key milliseconds` | 1 or 0 | O(1) | 毫秒级过期 |
| `TTL key` | seconds / -1 / -2 | O(1) | 剩余存活秒数 |
| `PTTL key` | milliseconds | O(1) | 剩余存活毫秒 |
| `EXPIREAT key timestamp` | 1 or 0 | O(1) | 按 Unix 时间戳过期 |
| `KEYS pattern` | matching keys | **O(N)** | ⛔ 全库扫描,生产禁用! |
| `SCAN cursor MATCH pattern COUNT n` | cursor, keys | **增量迭代 O(1)** | ✅ 安全的模糊查找 |
| `DBSIZE` | count | O(1) | 当前数据库 key 总数 |
| `SELECT index` | OK | O(1) | 切换数据库(0~15) |
| `FLUSHDB` | OK | O(N) | 清空当前库 |
| `FLUSHALL` | OK | O(N) | 清空所有库 |
| `TYPE key` | string/hash/list... | O(1) | 查看数据类型 |
| `MOVE key db` | 1 or 0 | O(1) | 移动到其他数据库(集群不支持) |
| `RENAME key newkey` | OK | O(1) | 重命名(不管类型) |
| `RANDOMKEY` | key / nil | O(1) | 随机返回一个 key(集群不支持) |
```go
// 优雅删除大 key——避免 DEL 阻塞主线程
keys := []string{"large:key1", "large:key2"}
rdb.Del(ctx, keys...).Err() // 小批量 DEL
// 或者用 SSCAN/HSCAN 分批删除字段
iter := rdb.HScan(ctx, "big:hash", 0, "", 100).Iterator()
for iter.Next(ctx) {
rdb.HDel(ctx, "big:hash", iter.Val()...)
}
```
> [!WARNING] TTL 的陷阱
> - `TTL` 返回 `-1` 表示 key 存在但无过期时间,`-2` 表示 key 不存在
> - Redis 的过期键删除是**惰性删除 + 定期删除**混合策略,不能保证设置 EXPIRE 后立即清理
> - 集群模式下 `MOVE`、`RANDOMKEY`、`FLUSHALL` **不可用**
## SCAN vs KEYS 深度对比
```bash
# ⛔ KEYS — 阻塞整个服务
KEYS user:*
# 100 万 key 中匹配 1000 个 → 主线程阻塞数百毫秒甚至秒级
# ✅ SCAN — 增量迭代,每次 O(1)
SCAN 0 MATCH user:* COUNT 100
# 返回游标 + 一小批匹配 key → 用游标继续,直到游标回到 0
```
```go
// Go 中的 SCAN 用法
iter := rdb.Scan(ctx, 0, "user:prefix:*", 100).Iterator()
for iter.Next(ctx) {
fmt.Println(iter.Val())
}
// 最后检查 iter.Err()
```
> [!WARNING] SCAN 的不确定性
> - 某个 key 可能返回多次(中间被修改或删除)
> - 某些匹配的 key 可能不返回
> - 因此 **不要用 SCAN 做统计计数**,只能用于清理或迁移等容错场景
## 管道 Pipeline vs 事务 Transaction
Redis 协议本身就是 request/response,Pipeline 把多个命令打包一次发送,大幅减少网络往返;而事务通过 `MULTI` / `EXEC` 保证一组命令的**原子执行**。
### Pipeline —— 批量发送,减少 RTT
```go
pipe := rdb.Pipeline()
pipe.Set(ctx, "k1", "v1", 0)
pipe.Set(ctx, "k2", "v2", 0)
pipe.Set(ctx, "k3", "v3", 0)
results, err := pipe.Exec(ctx) // 一次性发送,一次性接收
```
```bash
# CLI 模式
redis-cli --pipeline <<< $'SET k1 v1\nSET k2 v2\nSET k3 v3'
```
> [!TIP] Pipeline 不是银弹
> 单次 batch 控制在 50~200 条为佳。过大反而会增加 RTT 等待时间,且占用服务端协程。
### MULTI / EXEC —— 原子化执行
```go
pipe, cancel := rdb.TxPipeline()
defer cancel()
pipe.Set(ctx, "acc:A", "900", 0)
pipe.Set(ctx, "acc:B", "1100", 0)
_, err := pipe.Exec(ctx) // 全部命令依次执行(不被其他命令打断)
```
```bash
# Redis CLI 中的事务
MULTI
> SET acc:A 900
> SET acc:B 1100
EXEC # 原子提交
```
> [!NOTE] Pipeline vs Transaction 对比
> | 维度 | Pipeline | Transaction (MULTI/EXEC) |
> |------|----------|------------------------|
> | **目的** | 减少网络往返(性能) | 保证原子性(一致性) |
> | **命令失败处理** | 单个失败不影响其他命令 | `EXEC` 前语法错误会取消整个事务 |
> | **WATCH 支持** | 不支持 | 支持乐观锁 (`WATCH key`) |
> | **适用场景** | 批量写入、批量查询 | 转账、库存扣减等需要原子性的操作 |
> [!WARNING] Redis 事务不是"数据库事务"
> Redis 事务只保证**不中断**(没有回滚),中间执行的命令如果出错,后续命令仍会继续。如果需要"出错就回滚"的行为,请使用 Lua 脚本。
## 关联笔记
- [[hhs/Redis/02-核心数据类型]] — 每种类型的底层编码原理
- [[hhs/Redis/05-AOF持久化]] — 持久化策略对性能的影响
- [[hhs/Redis/09-高级特性]] — Pipeline / Lua / 事务详解