- 将主键从自增id改为GUID格式并添加格式校验 - 为service_mask添加表达式索引优化首位查询性能 - 更新相关文档说明改造方案与验证步骤 - 添加统计模块记录数据库写入与Kafka消费量 - 重构Redis心跳协议改用LIST类型存储项目状态 - 修复部署脚本中的服务名称不一致问题
2.7 KiB
2.7 KiB
service_mask 索引性能对比报告
结论摘要(如何判定“提升”)
- 在
service_mask位运算过滤场景中,新增idx_service_mask_first_bit后,查询计划应从Seq Scan转为Index Scan/Bitmap Index Scan(并触发分区裁剪时,仅扫描命中的分区)。 - 若过滤选择性较高(例如仅小比例满足 “&1=1”),通常能显著降低 IO 与响应时间。
索引脚本
- 结构与索引创建包含在:
scripts/db/010_heartbeat_schema.sqlscripts/db/020_partitioning_auto_daily.sql
- 关键语句:
CREATE INDEX idx_service_mask_first_bit ON heartbeat.heartbeat_events ((service_mask & 1));
测试方法(可复现)
1) 数据准备
建议在测试库中写入至少 100 万行,保证计划稳定:
SELECT heartbeat.ensure_partitions(current_date, current_date + 1);
INSERT INTO heartbeat.heartbeat_events (
ts_ms, hotel_id, room_id, device_id, ip,
power_state, guest_type, cardless_state, service_mask,
pms_state, carbon_state, device_count, comm_seq, extra
)
SELECT
(extract(epoch from now()) * 1000)::bigint + (g % 86400000),
(g % 1000)::int2,
('R' || (g % 500))::varchar(50),
('D' || (g % 20000))::varchar(64),
'127.0.0.1:1',
1, 0, 0,
(g % 1024)::bigint,
0, 0, 1, (g % 100000)::int4,
jsonb_build_object('src','bench')
FROM generate_series(1, 1000000) g;
ANALYZE heartbeat.heartbeat_events;
2) 对比维度
- 响应时间:
EXPLAIN (ANALYZE, BUFFERS)的Execution Time - QPS:用同一 SQL 连续执行 N 次(例如 1000 次)并统计平均耗时(由压测端计算)
- 查询形态:
- 形态 A(位运算表达式,命中表达式索引):
WHERE (service_mask & 1) = 1
- 形态 A(位运算表达式,命中表达式索引):
修改前/后对比(需要在目标环境产出)
说明:不同硬件/数据分布/缓存命中会导致数值差异。以下对比表格请在你的环境执行本报告“测试方法”并填入实际输出。
A. 修改前(无 idx_service_mask_first_bit)
- 查询计划(期望:Seq Scan 或 Bitmap Heap Scan + BRIN):
EXPLAIN (ANALYZE, BUFFERS)
SELECT count(*)
FROM heartbeat.heartbeat_events
WHERE (service_mask & 1) = 1;
- 结果记录:
- QPS(1000 次):____
- P50 响应时间(ms):____
- P95 响应时间(ms):____
B. 修改后(有 idx_service_mask_first_bit)
EXPLAIN (ANALYZE, BUFFERS)
SELECT count(*)
FROM heartbeat.heartbeat_events
WHERE (service_mask & 1) = 1;
- 结果记录:
- 位运算表达式命中索引(期望:Index/Bitmap Index Scan):
- QPS(1000 次):____
- P50(ms):____
- P95(ms):____
- 位运算表达式命中索引(期望:Index/Bitmap Index Scan):
结论与建议
- 业务使用
WHERE (service_mask & 1) = 1可直接命中idx_service_mask_first_bit。