这个是 TiDB 时序场景的经典表设计问题。逐个答:
问题 1 方案取舍:你 1.8w QPS + 时序范围查询,选 方案 B(自增 + SHARD + 分区)。
核心原因:
AUTO_RANDOM主键的设计意图是给"无时序字段"或"多业务混合"的场景用的——把随机后缀塞进主键来打散写入。一旦你有明确的create_time时序字段,用AUTO_RANDOM等于"用主键假装成时序,再额外为时序加索引",多绕一道。- 方案 A 的
(create_time, ...)联合索引在 1.8w QPS 下是新的写入瓶颈——索引本身在 TiKV 里也是有顺序的(按create_time排序写入),时序写入会聚到索引的尾部,形成索引热点。 - 方案 B 的
RANGE PARTITION BY (create_time)让时序查询走 partition pruning 极快,且SHARD_ROW_ID_BITS已经把写入分散到 N 个 region,两全。
问题 2 AUTO_RANDOM bit 位:
AUTO_RANDOM(N) 的 N 是随机后缀的 bit 数,跟 QPS 没直接关系,跟 总数据量 有关:
- N bit 提供 2^N 个不同随机后缀,**只要远小于总行数就行
- 默认 5 bit(32 种后缀)实际够用,主要给主键注入随机性打破单调
- 真正影响写入热点的不是 N 多少,而是主键是不是有序——有序=热点,无序=分散
- 你既然有时序字段,改走 SHARD + 分区,根本不需要 AUTO_RANDOM 操心 bit
问题 3 时序场景官方推荐范式:
sql
CREATE TABLE metric_log (
id BIGINT NOT NULL AUTO_INCREMENT,
create_time DATETIME(3) NOT NULL,
– 业务字段
device_id BIGINT,
value DOUBLE,
PRIMARY KEY (id) /*T![clustered_index] CLUSTERED */
) SHARD_ROW_ID_BITS = 4
PRE_SPLIT_REGIONS = 16
PARTITION BY RANGE (TO_DAYS(create_time)) (
PARTITION p202506 VALUES LESS THAN (TO_DAYS(‘2025-07-01’)),
PARTITION p202507 VALUES LESS THAN (TO_DAYS(‘2025-08-01’)),
PARTITION p202508 VALUES LESS THAN (TO_DAYS(‘2025-09-01’)),
– 按月分区,定期 ADD PARTITION
);
关键参数:
- `SHARD_ROW_ID_BITS = 4`:写入分散到 2^4 = 16 个 region
- `PRE_SPLIT_REGIONS = 16`:建表时就预分裂,避免开局单 region 热点
- `RANGE (TO_DAYS(create_time))`:时序查询 partition pruning,只扫命中的月分区
- 不用 AUTO_RANDOM(已经有 `create_time` 时序字段)
位宽经验值(QPS 1.8w 这种):
- `SHARD_ROW_ID_BITS = 4`(16 region)— 写入 QPS 2w 上下
- `SHARD_ROW_ID_BITS = 5`(32 region)— 写入 QPS 5w 上下
- `SHARD_ROW_ID_BITS = 6`(64 region)— 写入 QPS 10w+
你 1.8w 用 4 就够,预留 1 位给以后扩容。
操作建议(你眼前能立刻做的):
1. 改回 `AUTO_INCREMENT` 主键 + `SHARD_ROW_ID_BITS=4` + `PRE_SPLIT_REGIONS=16`
2. 按月 `RANGE PARTITION BY (create_time)`
3. 时序范围查询自动 partition pruning,延迟能下来
4. 写热点问题:`SHARD_ROW_ID_BITS` 配合后基本消除