- 将主键从自增id改为GUID格式并添加格式校验 - 为service_mask添加表达式索引优化首位查询性能 - 更新相关文档说明改造方案与验证步骤 - 添加统计模块记录数据库写入与Kafka消费量 - 重构Redis心跳协议改用LIST类型存储项目状态 - 修复部署脚本中的服务名称不一致问题
41 lines
2.2 KiB
Markdown
41 lines
2.2 KiB
Markdown
# GUID 主键与 service_mask 索引改造实施方案
|
||
|
||
## 目标
|
||
- 将 `heartbeat.heartbeat_events` 的主键从自增 `id` 改为 GUID(32 位无连字符 HEX 字符串)。
|
||
- 为 `service_mask` 的“首位(最低位)判断”新增表达式索引 `idx_service_mask_first_bit`,用于优化常见 bit 查询。
|
||
- 说明:你会删除现有数据库,因此不提供在线迁移流程,仅提供可重建的初始化脚本与验证步骤。
|
||
|
||
## 方案概述
|
||
### 1) 主键(GUID)
|
||
- 表字段 `guid` 使用 `varchar(32)` 并设置默认值 `replace(gen_random_uuid()::text, '-', '')`。
|
||
- 通过 `CHECK (guid ~ '^[0-9a-f]{32}$')` 约束输入格式为 32 位小写 HEX。
|
||
- 分区表使用组合主键 `PRIMARY KEY (ts_ms, guid)` 以满足 PostgreSQL 分区唯一约束要求(主键/唯一约束需包含分区键)。
|
||
|
||
### 2) service_mask 首位查询表达式索引
|
||
- 在父表创建索引:
|
||
- `CREATE INDEX idx_service_mask_first_bit ON heartbeat.heartbeat_events ((service_mask & 1));`
|
||
- 在按天分区创建索引:
|
||
- `idx_<partition>_service_mask_first_bit`
|
||
|
||
## 实施步骤(重建式)
|
||
1. 删除旧数据库/旧 schema(你将执行)。
|
||
2. 执行建表脚本:
|
||
- `scripts/db/010_heartbeat_schema.sql`
|
||
- `scripts/db/020_partitioning_auto_daily.sql`
|
||
3. 启动服务或执行 `npm run db:apply` 进行初始化。
|
||
4. 执行验证项:
|
||
- 确认 `heartbeat.heartbeat_events.guid` 为 `varchar(32)` 且存在默认值
|
||
- 确认存在 `idx_service_mask_first_bit`
|
||
- 确认分区新建后存在 `idx_<partition>_service_mask_first_bit`
|
||
|
||
## 风险评估
|
||
- GUID 默认生成依赖 `pgcrypto` 扩展:脚本已包含 `CREATE EXTENSION IF NOT EXISTS pgcrypto;`,但执行账号需要具备安装扩展权限。
|
||
- 分区表主键约束限制:无法实现“父表仅 guid 作为主键约束”,因此使用 `(ts_ms, guid)` 的组合主键。
|
||
- 表达式索引的表达式匹配:业务查询需要匹配索引表达式(详见 checklist),否则无法命中索引。
|
||
|
||
## 回滚步骤(重建式)
|
||
1. 停止服务写入。
|
||
2. `DROP SCHEMA heartbeat CASCADE;`(或删除数据库)。
|
||
3. 使用回滚版本的 SQL 脚本重新创建(例如回退到 `id bigserial` 版本的脚本)。
|
||
4. 重新启动服务并验证写入与查询。
|