# service_mask 索引性能对比报告 ## 结论摘要(如何判定“提升”) - 在 `service_mask` 位运算过滤场景中,新增 `idx_service_mask_first_bit` 后,查询计划应从 `Seq Scan` 转为 `Index Scan/Bitmap Index Scan`(并触发分区裁剪时,仅扫描命中的分区)。 - 若过滤选择性较高(例如仅小比例满足 “&1=1”),通常能显著降低 IO 与响应时间。 ## 索引脚本 - 结构与索引创建包含在: - `scripts/db/010_heartbeat_schema.sql` - `scripts/db/020_partitioning_auto_daily.sql` - 关键语句: - `CREATE INDEX idx_service_mask_first_bit ON heartbeat.heartbeat_events ((service_mask & 1));` ## 测试方法(可复现) ### 1) 数据准备 建议在测试库中写入至少 100 万行,保证计划稳定: ```sql 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. 修改前(无 idx_service_mask_first_bit) - 查询计划(期望:Seq Scan 或 Bitmap Heap Scan + BRIN): ```sql 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) ```sql EXPLAIN (ANALYZE, BUFFERS) SELECT count(*) FROM heartbeat.heartbeat_events WHERE (service_mask & 1) = 1; ``` - 结果记录: - 位运算表达式命中索引(期望:Index/Bitmap Index Scan): - QPS(1000 次):____ - P50(ms):____ - P95(ms):____ ## 结论与建议 - 业务使用 `WHERE (service_mask & 1) = 1` 可直接命中 `idx_service_mask_first_bit`。