feat: 添加分区表空间管理功能,优化分区表和索引的表空间设置

This commit is contained in:
2026-03-03 21:00:33 +08:00
parent 21ffef760f
commit 9165ce0bd0

View File

@@ -3,6 +3,8 @@ import dbManager from './databaseManager.js';
const PARENT_TABLE = 'rcu_action.rcu_action_events';
const PARTITION_TABLESPACE = 'ts_hot';
const PARTITION_SCHEMA = 'rcu_action';
const PARTITION_PREFIX = 'rcu_action_events_';
const PARENT_INDEX_STATEMENTS = [
'CREATE INDEX IF NOT EXISTS idx_rcu_action_hotel_id ON rcu_action.rcu_action_events (hotel_id);',
'CREATE INDEX IF NOT EXISTS idx_rcu_action_room_id ON rcu_action.rcu_action_events (room_id);',
@@ -14,6 +16,72 @@ const PARENT_INDEX_STATEMENTS = [
];
class PartitionManager {
toSqlTextLiteral(value) {
return `'${String(value).replace(/'/g, "''")}'`;
}
buildForceTablespaceSql({ schema, partition, tablespace }) {
return `
DO $$
DECLARE
v_schema text := ${this.toSqlTextLiteral(schema)};
v_partition text := ${this.toSqlTextLiteral(partition)};
v_hot text := ${this.toSqlTextLiteral(tablespace)};
v_part_oid oid;
v_toast_oid oid;
r record;
BEGIN
SELECT c.oid INTO v_part_oid
FROM pg_class c JOIN pg_namespace n ON n.oid = c.relnamespace
WHERE n.nspname = v_schema AND c.relname = v_partition AND c.relkind = 'r';
IF v_part_oid IS NULL THEN
RAISE EXCEPTION 'partition %.% not found', v_schema, v_partition;
END IF;
-- 1) 分区表对象 -> hot
EXECUTE format('ALTER TABLE %I.%I SET TABLESPACE %I', v_schema, v_partition, v_hot);
-- 2) 分区全部索引 -> hot
FOR r 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 = v_schema
AND t.relname = v_partition
AND COALESCE(ts.spcname, 'pg_default') <> v_hot
LOOP
EXECUTE format('ALTER INDEX %I.%I SET TABLESPACE %I', r.index_schema, r.index_name, v_hot);
END LOOP;
-- 3) TOAST 表 + TOAST 全部索引 -> hot若存在
SELECT reltoastrelid INTO v_toast_oid FROM pg_class WHERE oid = v_part_oid;
IF v_toast_oid IS NOT NULL AND v_toast_oid <> 0 THEN
EXECUTE format('ALTER TABLE %s SET TABLESPACE %I', v_toast_oid::regclass, v_hot);
FOR r IN
SELECT idxn.nspname AS index_schema, i.relname AS index_name
FROM pg_index x
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 x.indrelid = v_toast_oid
AND COALESCE(ts.spcname, 'pg_default') <> v_hot
LOOP
EXECUTE format('ALTER INDEX %I.%I SET TABLESPACE %I', r.index_schema, r.index_name, v_hot);
END LOOP;
END IF;
-- 4) 统计信息
EXECUTE format('ANALYZE %I.%I', v_schema, v_partition);
END $$;
`;
}
async ensureParentIndexes(client) {
for (const sql of PARENT_INDEX_STATEMENTS) {
await client.query(sql);
@@ -59,7 +127,8 @@ class PartitionManager {
targetDate.setDate(now.getDate() + i);
const { startMs, endMs, partitionSuffix } = this.getPartitionInfo(targetDate);
const partitionName = `rcu_action.rcu_action_events_${partitionSuffix}`;
const partitionTable = `${PARTITION_PREFIX}${partitionSuffix}`;
const partitionName = `${PARTITION_SCHEMA}.${partitionTable}`;
// Check if partition exists
const checkSql = `
@@ -76,6 +145,13 @@ class PartitionManager {
TABLESPACE ${PARTITION_TABLESPACE};
`;
await client.query(createSql);
const forceTablespaceSql = this.buildForceTablespaceSql({
schema: PARTITION_SCHEMA,
partition: partitionTable,
tablespace: PARTITION_TABLESPACE
});
await client.query(forceTablespaceSql);
}
}
logger.info('Partition check completed.');