feat: 实现GUID主键与service_mask索引改造

- 将主键从自增id改为GUID格式并添加格式校验
- 为service_mask添加表达式索引优化首位查询性能
- 更新相关文档说明改造方案与验证步骤
- 添加统计模块记录数据库写入与Kafka消费量
- 重构Redis心跳协议改用LIST类型存储项目状态
- 修复部署脚本中的服务名称不一致问题
This commit is contained in:
2026-01-17 18:37:44 +08:00
parent 662eeee380
commit 41301f9ce5
21 changed files with 828 additions and 106 deletions

View File

@@ -3,13 +3,15 @@
BEGIN;
CREATE EXTENSION IF NOT EXISTS pgcrypto;
CREATE SCHEMA IF NOT EXISTS heartbeat;
-- 主表(按 ts_ms 日分区)
-- 说明PostgreSQL 分区表的 PRIMARY KEY 通常需要包含分区键。
-- 这里使用 (ts_ms, id) 作为主键以保证可创建且可执行。
-- 这里使用 (ts_ms, guid) 作为主键以保证可创建且可执行。
CREATE TABLE IF NOT EXISTS heartbeat.heartbeat_events (
id bigserial,
guid varchar(32) NOT NULL DEFAULT replace(gen_random_uuid()::text, '-', ''),
ts_ms bigint NOT NULL,
hotel_id int2 NOT NULL,
@@ -43,7 +45,8 @@ CREATE TABLE IF NOT EXISTS heartbeat.heartbeat_events (
-- 弹性字段:电参/空调等(后续可结构化拆列;当前先放 extra
extra jsonb,
CONSTRAINT heartbeat_events_pk PRIMARY KEY (ts_ms, id),
CONSTRAINT heartbeat_events_pk PRIMARY KEY (ts_ms, guid),
CONSTRAINT chk_guid_32_hex CHECK (guid ~ '^[0-9a-f]{32}$'),
-- CHECK 约束:先做“非负+上界”约束(避免未来枚举扩展导致写入失败)
CONSTRAINT chk_ts_ms_positive CHECK (ts_ms > 0),
@@ -84,6 +87,9 @@ CREATE INDEX IF NOT EXISTS idx_heartbeat_events_device_id ON heartbeat.heartbeat
-- 说明BRIN 对“随时间递增且有相关性”的列收益更大service_mask 若不具备相关性,收益可能有限。
CREATE INDEX IF NOT EXISTS idx_heartbeat_events_service_mask_brin ON heartbeat.heartbeat_events USING BRIN (service_mask);
CREATE INDEX IF NOT EXISTS idx_service_mask_first_bit
ON heartbeat.heartbeat_events ((service_mask & 1));
-- 高价值附加索引(不在需求强制列表内):常见查询是 hotel_id + 时间范围
-- 若不希望额外索引,可注释掉
CREATE INDEX IF NOT EXISTS idx_heartbeat_events_hotel_ts ON heartbeat.heartbeat_events (hotel_id, ts_ms);

View File

@@ -61,6 +61,7 @@ BEGIN
EXECUTE format('CREATE INDEX IF NOT EXISTS %I ON heartbeat.%I (guest_type);', 'idx_'||part_name||'_guest_type', part_name);
EXECUTE format('CREATE INDEX IF NOT EXISTS %I ON heartbeat.%I (device_id);', 'idx_'||part_name||'_device_id', part_name);
EXECUTE format('CREATE INDEX IF NOT EXISTS %I ON heartbeat.%I USING BRIN (service_mask);', 'idx_'||part_name||'_service_mask_brin', part_name);
EXECUTE format('CREATE INDEX IF NOT EXISTS %I ON heartbeat.%I ((service_mask & 1));', 'idx_'||part_name||'_service_mask_first_bit', part_name);
EXECUTE format('CREATE INDEX IF NOT EXISTS %I ON heartbeat.%I (hotel_id, ts_ms);', 'idx_'||part_name||'_hotel_ts', part_name);
END;
$$;