feat: 新增 G4 热表独立双写能力
- 新增配置项以支持旧/新明细表的独立写入开关及目标表名。 - 重构 DatabaseManager,抽象通用批量 COPY 写入内核,支持不同目标表的复用。 - 新增双明细写入编排器,支持旧/新表独立执行、重试及 fallback。 - 调整 HeartbeatProcessor.processBatch(),确保 room_status 独立执行。 - 错误表仅记录新表写入失败,旧表失败不再写入错误表。 - 重新定义消费暂停策略,基于当前启用的关键 sink 判断。 - 补充按 sink 维度的统计项与启动日志。 新增 G4 热表相关的数据库规范与处理逻辑,确保系统在双写模式下的稳定性与可扩展性。
This commit is contained in:
530
docs/heartbeat_events_g4_hot.sql
Normal file
530
docs/heartbeat_events_g4_hot.sql
Normal file
@@ -0,0 +1,530 @@
|
||||
/*
|
||||
Navicat Premium Dump SQL
|
||||
|
||||
Source Server : FnOS 109
|
||||
Source Server Type : PostgreSQL
|
||||
Source Server Version : 150014 (150014)
|
||||
Source Host : 10.8.8.109:5433
|
||||
Source Catalog : log_platform
|
||||
Source Schema : heartbeat
|
||||
|
||||
Target Server Type : PostgreSQL
|
||||
Target Server Version : 150014 (150014)
|
||||
File Encoding : 65001
|
||||
|
||||
Date: 09/03/2026 10:11:03
|
||||
*/
|
||||
|
||||
|
||||
-- ----------------------------
|
||||
-- Table structure for heartbeat_events_g4_hot_d20260301
|
||||
-- ----------------------------
|
||||
DROP TABLE IF EXISTS "heartbeat"."heartbeat_events_g4_hot_d20260301";
|
||||
CREATE TABLE "heartbeat"."heartbeat_events_g4_hot_d20260301" (
|
||||
"ts_ms" int8 NOT NULL,
|
||||
"hotel_id" int2 NOT NULL,
|
||||
"room_id" varchar(50) COLLATE "pg_catalog"."default" NOT NULL,
|
||||
"device_id" varchar(64) COLLATE "pg_catalog"."default" NOT NULL,
|
||||
"ip" varchar(21) COLLATE "pg_catalog"."default" NOT NULL,
|
||||
"power_state" int2 NOT NULL,
|
||||
"guest_type" int2 NOT NULL,
|
||||
"cardless_state" int2 NOT NULL,
|
||||
"service_mask" int8 NOT NULL,
|
||||
"pms_state" int2 NOT NULL,
|
||||
"carbon_state" int2 NOT NULL,
|
||||
"device_count" int2 NOT NULL,
|
||||
"comm_seq" int4 NOT NULL,
|
||||
"elec_address" _text COLLATE "pg_catalog"."default",
|
||||
"air_address" _text COLLATE "pg_catalog"."default",
|
||||
"voltage" _float8,
|
||||
"ampere" _float8,
|
||||
"power" _float8,
|
||||
"phase" _text COLLATE "pg_catalog"."default",
|
||||
"energy" _float8,
|
||||
"sum_energy" _float8,
|
||||
"state" _int2,
|
||||
"model" _int2,
|
||||
"speed" _int2,
|
||||
"set_temp" _int2,
|
||||
"now_temp" _int2,
|
||||
"solenoid_valve" _int2,
|
||||
"extra" jsonb,
|
||||
"write_ts_ms" int8 NOT NULL DEFAULT ((EXTRACT(epoch FROM clock_timestamp()) * (1000)::numeric))::bigint,
|
||||
"insert_card" int2,
|
||||
"bright_g" int2,
|
||||
"version" int2,
|
||||
"svc_01" bool,
|
||||
"svc_02" bool,
|
||||
"svc_03" bool,
|
||||
"svc_04" bool,
|
||||
"svc_05" bool,
|
||||
"svc_06" bool,
|
||||
"svc_07" bool,
|
||||
"svc_08" bool,
|
||||
"svc_09" bool,
|
||||
"svc_10" bool,
|
||||
"svc_11" bool,
|
||||
"svc_12" bool,
|
||||
"svc_13" bool,
|
||||
"svc_14" bool,
|
||||
"svc_15" bool,
|
||||
"svc_16" bool,
|
||||
"svc_17" bool,
|
||||
"svc_18" bool,
|
||||
"svc_19" bool,
|
||||
"svc_20" bool,
|
||||
"svc_21" bool,
|
||||
"svc_22" bool,
|
||||
"svc_23" bool,
|
||||
"svc_24" bool,
|
||||
"svc_25" bool,
|
||||
"svc_26" bool,
|
||||
"svc_27" bool,
|
||||
"svc_28" bool,
|
||||
"svc_29" bool,
|
||||
"svc_30" bool,
|
||||
"svc_31" bool,
|
||||
"svc_32" bool,
|
||||
"svc_33" bool,
|
||||
"svc_34" bool,
|
||||
"svc_35" bool,
|
||||
"svc_36" bool,
|
||||
"svc_37" bool,
|
||||
"svc_38" bool,
|
||||
"svc_39" bool,
|
||||
"svc_40" bool,
|
||||
"svc_41" bool,
|
||||
"svc_42" bool,
|
||||
"svc_43" bool,
|
||||
"svc_44" bool,
|
||||
"svc_45" bool,
|
||||
"svc_46" bool,
|
||||
"svc_47" bool,
|
||||
"svc_48" bool,
|
||||
"svc_49" bool,
|
||||
"svc_50" bool,
|
||||
"svc_51" bool,
|
||||
"svc_52" bool,
|
||||
"svc_53" bool,
|
||||
"svc_54" bool,
|
||||
"svc_55" bool,
|
||||
"svc_56" bool,
|
||||
"svc_57" bool,
|
||||
"svc_58" bool,
|
||||
"svc_59" bool,
|
||||
"svc_60" bool,
|
||||
"svc_61" bool,
|
||||
"svc_62" bool,
|
||||
"svc_63" bool,
|
||||
"svc_64" bool,
|
||||
"air_address_1" text COLLATE "pg_catalog"."default",
|
||||
"air_address_2" text COLLATE "pg_catalog"."default",
|
||||
"air_address_residual" _text COLLATE "pg_catalog"."default",
|
||||
"state_1" int2,
|
||||
"state_2" int2,
|
||||
"state_residual" _int2,
|
||||
"model_1" int2,
|
||||
"model_2" int2,
|
||||
"model_residual" _int2,
|
||||
"speed_1" int2,
|
||||
"speed_2" int2,
|
||||
"speed_residual" _int2,
|
||||
"set_temp_1" int2,
|
||||
"set_temp_2" int2,
|
||||
"set_temp_residual" _int2,
|
||||
"now_temp_1" int2,
|
||||
"now_temp_2" int2,
|
||||
"now_temp_residual" _int2,
|
||||
"solenoid_valve_1" int2,
|
||||
"solenoid_valve_2" int2,
|
||||
"solenoid_valve_residual" _int2,
|
||||
"elec_address_1" text COLLATE "pg_catalog"."default",
|
||||
"elec_address_2" text COLLATE "pg_catalog"."default",
|
||||
"elec_address_residual" _text COLLATE "pg_catalog"."default",
|
||||
"voltage_1" float8,
|
||||
"voltage_2" float8,
|
||||
"voltage_residual" _float8,
|
||||
"ampere_1" float8,
|
||||
"ampere_2" float8,
|
||||
"ampere_residual" _float8,
|
||||
"power_1" float8,
|
||||
"power_2" float8,
|
||||
"power_residual" _float8,
|
||||
"phase_1" text COLLATE "pg_catalog"."default",
|
||||
"phase_2" text COLLATE "pg_catalog"."default",
|
||||
"phase_residual" _text COLLATE "pg_catalog"."default",
|
||||
"energy_1" float8,
|
||||
"energy_2" float8,
|
||||
"energy_residual" _float8,
|
||||
"sum_energy_1" float8,
|
||||
"sum_energy_2" float8,
|
||||
"sum_energy_residual" _float8,
|
||||
"power_carbon_on" float8,
|
||||
"power_carbon_off" float8,
|
||||
"power_person_exist" float8,
|
||||
"power_person_left" float8,
|
||||
"guid" varchar(32) COLLATE "pg_catalog"."default"
|
||||
)
|
||||
TABLESPACE "ts_hot"
|
||||
;
|
||||
|
||||
-- ----------------------------
|
||||
-- Table structure for heartbeat_events_g4_hot_d20260302
|
||||
-- ----------------------------
|
||||
DROP TABLE IF EXISTS "heartbeat"."heartbeat_events_g4_hot_d20260302";
|
||||
CREATE TABLE "heartbeat"."heartbeat_events_g4_hot_d20260302" (
|
||||
"ts_ms" int8 NOT NULL,
|
||||
"hotel_id" int2 NOT NULL,
|
||||
"room_id" varchar(50) COLLATE "pg_catalog"."default" NOT NULL,
|
||||
"device_id" varchar(64) COLLATE "pg_catalog"."default" NOT NULL,
|
||||
"ip" varchar(21) COLLATE "pg_catalog"."default" NOT NULL,
|
||||
"power_state" int2 NOT NULL,
|
||||
"guest_type" int2 NOT NULL,
|
||||
"cardless_state" int2 NOT NULL,
|
||||
"service_mask" int8 NOT NULL,
|
||||
"pms_state" int2 NOT NULL,
|
||||
"carbon_state" int2 NOT NULL,
|
||||
"device_count" int2 NOT NULL,
|
||||
"comm_seq" int4 NOT NULL,
|
||||
"elec_address" _text COLLATE "pg_catalog"."default",
|
||||
"air_address" _text COLLATE "pg_catalog"."default",
|
||||
"voltage" _float8,
|
||||
"ampere" _float8,
|
||||
"power" _float8,
|
||||
"phase" _text COLLATE "pg_catalog"."default",
|
||||
"energy" _float8,
|
||||
"sum_energy" _float8,
|
||||
"state" _int2,
|
||||
"model" _int2,
|
||||
"speed" _int2,
|
||||
"set_temp" _int2,
|
||||
"now_temp" _int2,
|
||||
"solenoid_valve" _int2,
|
||||
"extra" jsonb,
|
||||
"write_ts_ms" int8 NOT NULL DEFAULT ((EXTRACT(epoch FROM clock_timestamp()) * (1000)::numeric))::bigint,
|
||||
"insert_card" int2,
|
||||
"bright_g" int2,
|
||||
"version" int2,
|
||||
"svc_01" bool,
|
||||
"svc_02" bool,
|
||||
"svc_03" bool,
|
||||
"svc_04" bool,
|
||||
"svc_05" bool,
|
||||
"svc_06" bool,
|
||||
"svc_07" bool,
|
||||
"svc_08" bool,
|
||||
"svc_09" bool,
|
||||
"svc_10" bool,
|
||||
"svc_11" bool,
|
||||
"svc_12" bool,
|
||||
"svc_13" bool,
|
||||
"svc_14" bool,
|
||||
"svc_15" bool,
|
||||
"svc_16" bool,
|
||||
"svc_17" bool,
|
||||
"svc_18" bool,
|
||||
"svc_19" bool,
|
||||
"svc_20" bool,
|
||||
"svc_21" bool,
|
||||
"svc_22" bool,
|
||||
"svc_23" bool,
|
||||
"svc_24" bool,
|
||||
"svc_25" bool,
|
||||
"svc_26" bool,
|
||||
"svc_27" bool,
|
||||
"svc_28" bool,
|
||||
"svc_29" bool,
|
||||
"svc_30" bool,
|
||||
"svc_31" bool,
|
||||
"svc_32" bool,
|
||||
"svc_33" bool,
|
||||
"svc_34" bool,
|
||||
"svc_35" bool,
|
||||
"svc_36" bool,
|
||||
"svc_37" bool,
|
||||
"svc_38" bool,
|
||||
"svc_39" bool,
|
||||
"svc_40" bool,
|
||||
"svc_41" bool,
|
||||
"svc_42" bool,
|
||||
"svc_43" bool,
|
||||
"svc_44" bool,
|
||||
"svc_45" bool,
|
||||
"svc_46" bool,
|
||||
"svc_47" bool,
|
||||
"svc_48" bool,
|
||||
"svc_49" bool,
|
||||
"svc_50" bool,
|
||||
"svc_51" bool,
|
||||
"svc_52" bool,
|
||||
"svc_53" bool,
|
||||
"svc_54" bool,
|
||||
"svc_55" bool,
|
||||
"svc_56" bool,
|
||||
"svc_57" bool,
|
||||
"svc_58" bool,
|
||||
"svc_59" bool,
|
||||
"svc_60" bool,
|
||||
"svc_61" bool,
|
||||
"svc_62" bool,
|
||||
"svc_63" bool,
|
||||
"svc_64" bool,
|
||||
"air_address_1" text COLLATE "pg_catalog"."default",
|
||||
"air_address_2" text COLLATE "pg_catalog"."default",
|
||||
"air_address_residual" _text COLLATE "pg_catalog"."default",
|
||||
"state_1" int2,
|
||||
"state_2" int2,
|
||||
"state_residual" _int2,
|
||||
"model_1" int2,
|
||||
"model_2" int2,
|
||||
"model_residual" _int2,
|
||||
"speed_1" int2,
|
||||
"speed_2" int2,
|
||||
"speed_residual" _int2,
|
||||
"set_temp_1" int2,
|
||||
"set_temp_2" int2,
|
||||
"set_temp_residual" _int2,
|
||||
"now_temp_1" int2,
|
||||
"now_temp_2" int2,
|
||||
"now_temp_residual" _int2,
|
||||
"solenoid_valve_1" int2,
|
||||
"solenoid_valve_2" int2,
|
||||
"solenoid_valve_residual" _int2,
|
||||
"elec_address_1" text COLLATE "pg_catalog"."default",
|
||||
"elec_address_2" text COLLATE "pg_catalog"."default",
|
||||
"elec_address_residual" _text COLLATE "pg_catalog"."default",
|
||||
"voltage_1" float8,
|
||||
"voltage_2" float8,
|
||||
"voltage_residual" _float8,
|
||||
"ampere_1" float8,
|
||||
"ampere_2" float8,
|
||||
"ampere_residual" _float8,
|
||||
"power_1" float8,
|
||||
"power_2" float8,
|
||||
"power_residual" _float8,
|
||||
"phase_1" text COLLATE "pg_catalog"."default",
|
||||
"phase_2" text COLLATE "pg_catalog"."default",
|
||||
"phase_residual" _text COLLATE "pg_catalog"."default",
|
||||
"energy_1" float8,
|
||||
"energy_2" float8,
|
||||
"energy_residual" _float8,
|
||||
"sum_energy_1" float8,
|
||||
"sum_energy_2" float8,
|
||||
"sum_energy_residual" _float8,
|
||||
"power_carbon_on" float8,
|
||||
"power_carbon_off" float8,
|
||||
"power_person_exist" float8,
|
||||
"power_person_left" float8,
|
||||
"guid" varchar(32) COLLATE "pg_catalog"."default"
|
||||
)
|
||||
TABLESPACE "ts_hot"
|
||||
;
|
||||
|
||||
-- ----------------------------
|
||||
-- Table structure for heartbeat_events_g4_hot
|
||||
-- ----------------------------
|
||||
DROP TABLE IF EXISTS "heartbeat"."heartbeat_events_g4_hot";
|
||||
CREATE TABLE "heartbeat"."heartbeat_events_g4_hot" (
|
||||
"ts_ms" int8 NOT NULL,
|
||||
"hotel_id" int2 NOT NULL,
|
||||
"room_id" varchar(50) COLLATE "pg_catalog"."default" NOT NULL,
|
||||
"device_id" varchar(64) COLLATE "pg_catalog"."default" NOT NULL,
|
||||
"ip" varchar(21) COLLATE "pg_catalog"."default" NOT NULL,
|
||||
"power_state" int2 NOT NULL,
|
||||
"guest_type" int2 NOT NULL,
|
||||
"cardless_state" int2 NOT NULL,
|
||||
"service_mask" int8 NOT NULL,
|
||||
"pms_state" int2 NOT NULL,
|
||||
"carbon_state" int2 NOT NULL,
|
||||
"device_count" int2 NOT NULL,
|
||||
"comm_seq" int4 NOT NULL,
|
||||
"elec_address" text[] COLLATE "pg_catalog"."default",
|
||||
"air_address" text[] COLLATE "pg_catalog"."default",
|
||||
"voltage" float8[],
|
||||
"ampere" float8[],
|
||||
"power" float8[],
|
||||
"phase" text[] COLLATE "pg_catalog"."default",
|
||||
"energy" float8[],
|
||||
"sum_energy" float8[],
|
||||
"state" int2[],
|
||||
"model" int2[],
|
||||
"speed" int2[],
|
||||
"set_temp" int2[],
|
||||
"now_temp" int2[],
|
||||
"solenoid_valve" int2[],
|
||||
"extra" jsonb,
|
||||
"write_ts_ms" int8 NOT NULL DEFAULT ((EXTRACT(epoch FROM clock_timestamp()) * (1000)::numeric))::bigint,
|
||||
"insert_card" int2,
|
||||
"bright_g" int2,
|
||||
"version" int2,
|
||||
"svc_01" bool,
|
||||
"svc_02" bool,
|
||||
"svc_03" bool,
|
||||
"svc_04" bool,
|
||||
"svc_05" bool,
|
||||
"svc_06" bool,
|
||||
"svc_07" bool,
|
||||
"svc_08" bool,
|
||||
"svc_09" bool,
|
||||
"svc_10" bool,
|
||||
"svc_11" bool,
|
||||
"svc_12" bool,
|
||||
"svc_13" bool,
|
||||
"svc_14" bool,
|
||||
"svc_15" bool,
|
||||
"svc_16" bool,
|
||||
"svc_17" bool,
|
||||
"svc_18" bool,
|
||||
"svc_19" bool,
|
||||
"svc_20" bool,
|
||||
"svc_21" bool,
|
||||
"svc_22" bool,
|
||||
"svc_23" bool,
|
||||
"svc_24" bool,
|
||||
"svc_25" bool,
|
||||
"svc_26" bool,
|
||||
"svc_27" bool,
|
||||
"svc_28" bool,
|
||||
"svc_29" bool,
|
||||
"svc_30" bool,
|
||||
"svc_31" bool,
|
||||
"svc_32" bool,
|
||||
"svc_33" bool,
|
||||
"svc_34" bool,
|
||||
"svc_35" bool,
|
||||
"svc_36" bool,
|
||||
"svc_37" bool,
|
||||
"svc_38" bool,
|
||||
"svc_39" bool,
|
||||
"svc_40" bool,
|
||||
"svc_41" bool,
|
||||
"svc_42" bool,
|
||||
"svc_43" bool,
|
||||
"svc_44" bool,
|
||||
"svc_45" bool,
|
||||
"svc_46" bool,
|
||||
"svc_47" bool,
|
||||
"svc_48" bool,
|
||||
"svc_49" bool,
|
||||
"svc_50" bool,
|
||||
"svc_51" bool,
|
||||
"svc_52" bool,
|
||||
"svc_53" bool,
|
||||
"svc_54" bool,
|
||||
"svc_55" bool,
|
||||
"svc_56" bool,
|
||||
"svc_57" bool,
|
||||
"svc_58" bool,
|
||||
"svc_59" bool,
|
||||
"svc_60" bool,
|
||||
"svc_61" bool,
|
||||
"svc_62" bool,
|
||||
"svc_63" bool,
|
||||
"svc_64" bool,
|
||||
"air_address_1" text COLLATE "pg_catalog"."default",
|
||||
"air_address_2" text COLLATE "pg_catalog"."default",
|
||||
"air_address_residual" text[] COLLATE "pg_catalog"."default",
|
||||
"state_1" int2,
|
||||
"state_2" int2,
|
||||
"state_residual" int2[],
|
||||
"model_1" int2,
|
||||
"model_2" int2,
|
||||
"model_residual" int2[],
|
||||
"speed_1" int2,
|
||||
"speed_2" int2,
|
||||
"speed_residual" int2[],
|
||||
"set_temp_1" int2,
|
||||
"set_temp_2" int2,
|
||||
"set_temp_residual" int2[],
|
||||
"now_temp_1" int2,
|
||||
"now_temp_2" int2,
|
||||
"now_temp_residual" int2[],
|
||||
"solenoid_valve_1" int2,
|
||||
"solenoid_valve_2" int2,
|
||||
"solenoid_valve_residual" int2[],
|
||||
"elec_address_1" text COLLATE "pg_catalog"."default",
|
||||
"elec_address_2" text COLLATE "pg_catalog"."default",
|
||||
"elec_address_residual" text[] COLLATE "pg_catalog"."default",
|
||||
"voltage_1" float8,
|
||||
"voltage_2" float8,
|
||||
"voltage_residual" float8[],
|
||||
"ampere_1" float8,
|
||||
"ampere_2" float8,
|
||||
"ampere_residual" float8[],
|
||||
"power_1" float8,
|
||||
"power_2" float8,
|
||||
"power_residual" float8[],
|
||||
"phase_1" text COLLATE "pg_catalog"."default",
|
||||
"phase_2" text COLLATE "pg_catalog"."default",
|
||||
"phase_residual" text[] COLLATE "pg_catalog"."default",
|
||||
"energy_1" float8,
|
||||
"energy_2" float8,
|
||||
"energy_residual" float8[],
|
||||
"sum_energy_1" float8,
|
||||
"sum_energy_2" float8,
|
||||
"sum_energy_residual" float8[],
|
||||
"power_carbon_on" float8,
|
||||
"power_carbon_off" float8,
|
||||
"power_person_exist" float8,
|
||||
"power_person_left" float8,
|
||||
"guid" varchar(32) COLLATE "pg_catalog"."default"
|
||||
)
|
||||
PARTITION BY RANGE (
|
||||
"ts_ms" "pg_catalog"."int8_ops"
|
||||
)
|
||||
TABLESPACE "ts_hot"
|
||||
;
|
||||
ALTER TABLE "heartbeat"."heartbeat_events_g4_hot" ATTACH PARTITION "heartbeat"."heartbeat_events_g4_hot_d20260301" FOR VALUES FROM (
|
||||
'1772294400000'
|
||||
) TO (
|
||||
'1772380800000'
|
||||
)
|
||||
;
|
||||
ALTER TABLE "heartbeat"."heartbeat_events_g4_hot" ATTACH PARTITION "heartbeat"."heartbeat_events_g4_hot_d20260302" FOR VALUES FROM (
|
||||
'1772380800000'
|
||||
) TO (
|
||||
'1772467200000'
|
||||
)
|
||||
;
|
||||
|
||||
-- ----------------------------
|
||||
-- Indexes structure for table heartbeat_events_g4_hot_d20260301
|
||||
-- ----------------------------
|
||||
CREATE UNIQUE INDEX "heartbeat_events_g4_hot_d20260301_guid_ts_ms_idx" ON "heartbeat"."heartbeat_events_g4_hot_d20260301" USING btree (
|
||||
"guid" COLLATE "pg_catalog"."default" "pg_catalog"."text_ops" ASC NULLS LAST,
|
||||
"ts_ms" "pg_catalog"."int8_ops" ASC NULLS LAST
|
||||
) TABLESPACE "ts_hot";
|
||||
CREATE INDEX "heartbeat_events_g4_hot_d2026_hotel_id_room_id_device_id_ts_idx" ON "heartbeat"."heartbeat_events_g4_hot_d20260301" USING btree (
|
||||
"hotel_id" "pg_catalog"."int2_ops" ASC NULLS LAST,
|
||||
"room_id" COLLATE "pg_catalog"."default" "pg_catalog"."text_ops" ASC NULLS LAST,
|
||||
"device_id" COLLATE "pg_catalog"."default" "pg_catalog"."text_ops" ASC NULLS LAST,
|
||||
"ts_ms" "pg_catalog"."int8_ops" DESC NULLS FIRST
|
||||
) WITH (FILLFACTOR = 100) TABLESPACE "ts_hot";
|
||||
|
||||
-- ----------------------------
|
||||
-- Indexes structure for table heartbeat_events_g4_hot_d20260302
|
||||
-- ----------------------------
|
||||
CREATE UNIQUE INDEX "heartbeat_events_g4_hot_d20260302_guid_ts_ms_idx" ON "heartbeat"."heartbeat_events_g4_hot_d20260302" USING btree (
|
||||
"guid" COLLATE "pg_catalog"."default" "pg_catalog"."text_ops" ASC NULLS LAST,
|
||||
"ts_ms" "pg_catalog"."int8_ops" ASC NULLS LAST
|
||||
) TABLESPACE "ts_hot";
|
||||
CREATE INDEX "heartbeat_events_g4_hot_d2026_hotel_id_room_id_device_id_t_idx1" ON "heartbeat"."heartbeat_events_g4_hot_d20260302" USING btree (
|
||||
"hotel_id" "pg_catalog"."int2_ops" ASC NULLS LAST,
|
||||
"room_id" COLLATE "pg_catalog"."default" "pg_catalog"."text_ops" ASC NULLS LAST,
|
||||
"device_id" COLLATE "pg_catalog"."default" "pg_catalog"."text_ops" ASC NULLS LAST,
|
||||
"ts_ms" "pg_catalog"."int8_ops" DESC NULLS FIRST
|
||||
) WITH (FILLFACTOR = 100) TABLESPACE "ts_hot";
|
||||
|
||||
-- ----------------------------
|
||||
-- Indexes structure for table heartbeat_events_g4_hot
|
||||
-- ----------------------------
|
||||
CREATE UNIQUE INDEX "idx_g4_hot_guid_unique" ON "heartbeat"."heartbeat_events_g4_hot" USING btree (
|
||||
"guid" COLLATE "pg_catalog"."default" "pg_catalog"."text_ops" ASC NULLS LAST,
|
||||
"ts_ms" "pg_catalog"."int8_ops" ASC NULLS LAST
|
||||
) TABLESPACE "ts_hot";
|
||||
CREATE INDEX "idx_g4_hot_lookup" ON "heartbeat"."heartbeat_events_g4_hot" USING btree (
|
||||
"hotel_id" "pg_catalog"."int2_ops" ASC NULLS LAST,
|
||||
"room_id" COLLATE "pg_catalog"."default" "pg_catalog"."text_ops" ASC NULLS LAST,
|
||||
"device_id" COLLATE "pg_catalog"."default" "pg_catalog"."text_ops" ASC NULLS LAST,
|
||||
"ts_ms" "pg_catalog"."int8_ops" DESC NULLS FIRST
|
||||
) WITH (FILLFACTOR = 100) TABLESPACE "ts_hot";
|
||||
@@ -1,55 +0,0 @@
|
||||
-- 通过 docker compose 在容器内执行 psql,并使用 here-doc 传入 SQL
|
||||
docker compose exec -T postgres psql -U log_admin -d log_platform -v ON_ERROR_STOP=1 <<'SQL'
|
||||
|
||||
-- 使用匿名代码块批量处理分区创建与索引迁移
|
||||
DO $$
|
||||
DECLARE
|
||||
d date; -- 循环日期(从今天到未来 29 天)
|
||||
pname text; -- 分区表名,例如 heartbeat_events_20260303
|
||||
start_ms bigint; -- 分区起始毫秒时间戳(UTC,含)
|
||||
end_ms bigint; -- 分区结束毫秒时间戳(UTC,不含)
|
||||
idx record; -- 遍历分区索引时的游标记录
|
||||
BEGIN
|
||||
-- 生成从 current_date 到 current_date+29 的日期序列(共 30 天)
|
||||
FOR d IN
|
||||
SELECT generate_series(current_date, current_date + 29, interval '1 day')::date
|
||||
LOOP
|
||||
-- 按约定命名分区名:heartbeat_events_YYYYMMDD
|
||||
pname := format('heartbeat_events_%s', to_char(d, 'YYYYMMDD'));
|
||||
|
||||
-- 计算该日期 00:00:00 UTC 的毫秒时间戳作为分区下界
|
||||
start_ms := (extract(epoch from (d::timestamp at time zone 'UTC')) * 1000)::bigint;
|
||||
|
||||
-- 计算下一天 00:00:00 UTC 的毫秒时间戳作为分区上界
|
||||
end_ms := (extract(epoch from ((d + 1)::timestamp at time zone 'UTC')) * 1000)::bigint;
|
||||
|
||||
-- 若分区不存在则创建;存在则跳过(幂等)
|
||||
EXECUTE format(
|
||||
'CREATE TABLE IF NOT EXISTS heartbeat.%I PARTITION OF heartbeat.heartbeat_events FOR VALUES FROM (%s) TO (%s) TABLESPACE ts_hot',
|
||||
pname, start_ms, end_ms
|
||||
);
|
||||
|
||||
-- 无论新建或已存在,强制把分区表迁移到 ts_hot(保证热分区落热盘)
|
||||
EXECUTE format('ALTER TABLE heartbeat.%I SET TABLESPACE ts_hot', pname);
|
||||
|
||||
-- 遍历该分区的全部索引,筛出不在 ts_hot 的索引
|
||||
FOR idx IN
|
||||
SELECT idxn.nspname AS index_schema, i.relname AS index_name
|
||||
FROM pg_index x
|
||||
JOIN pg_class t ON t.oid = x.indrelid
|
||||
JOIN pg_namespace nt ON nt.oid = t.relnamespace
|
||||
JOIN pg_class i ON i.oid = x.indexrelid
|
||||
JOIN pg_namespace idxn ON idxn.oid = i.relnamespace
|
||||
LEFT JOIN pg_tablespace ts ON ts.oid = i.reltablespace
|
||||
WHERE nt.nspname = 'heartbeat'
|
||||
AND t.relname = pname
|
||||
AND COALESCE(ts.spcname, 'pg_default') <> 'ts_hot'
|
||||
LOOP
|
||||
-- 将索引迁移到 ts_hot,确保“分区与索引同盘”
|
||||
EXECUTE format('ALTER INDEX %I.%I SET TABLESPACE ts_hot', idx.index_schema, idx.index_name);
|
||||
END LOOP;
|
||||
END LOOP;
|
||||
END $$;
|
||||
|
||||
-- here-doc 结束标记
|
||||
SQL
|
||||
Reference in New Issue
Block a user