feat: 添加 relocate_partition_to_tablespace 函数以强制分区及其索引分配到指定表空间,并在创建日分区时调用该函数

This commit is contained in:
2026-03-03 21:00:49 +08:00
parent 2b529baeb3
commit 70e717ea5d
2 changed files with 132 additions and 0 deletions

View File

@@ -33,6 +33,70 @@ AS $$
SELECT format('heartbeat_events_%s', to_char(p_day, 'YYYYMMDD'));
$$;
-- 强制将分区及其索引分配到指定表空间(幂等)
CREATE OR REPLACE FUNCTION heartbeat.relocate_partition_to_tablespace(
p_schema text,
p_partition text,
p_tablespace text DEFAULT 'ts_hot'
)
RETURNS void
LANGUAGE plpgsql
AS $$
DECLARE
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 = p_schema
AND c.relname = p_partition
AND c.relkind = 'r';
IF v_part_oid IS NULL THEN
RAISE EXCEPTION 'partition %.% not found', p_schema, p_partition;
END IF;
-- 1) 分区表对象 -> 指定 tablespace
EXECUTE format('ALTER TABLE %I.%I SET TABLESPACE %I', p_schema, p_partition, p_tablespace);
-- 2) 分区全部索引 -> 指定 tablespace
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_part_oid
AND COALESCE(ts.spcname, 'pg_default') <> p_tablespace
LOOP
EXECUTE format('ALTER INDEX %I.%I SET TABLESPACE %I', r.index_schema, r.index_name, p_tablespace);
END LOOP;
-- 3) TOAST 表 + TOAST 索引 -> 指定 tablespace若存在
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, p_tablespace);
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') <> p_tablespace
LOOP
EXECUTE format('ALTER INDEX %I.%I SET TABLESPACE %I', r.index_schema, r.index_name, p_tablespace);
END LOOP;
END IF;
-- 4) 统计信息
EXECUTE format('ANALYZE %I.%I', p_schema, p_partition);
END;
$$;
-- 创建单日分区(幂等);父表索引自动继承到子表,无需手动建索引
CREATE OR REPLACE FUNCTION heartbeat.create_daily_partition(p_day date)
RETURNS void
@@ -51,6 +115,8 @@ BEGIN
'CREATE TABLE IF NOT EXISTS heartbeat.%I PARTITION OF heartbeat.heartbeat_events FOR VALUES FROM (%s) TO (%s) TABLESPACE ts_hot',
part_name, start_ms, end_ms
);
PERFORM heartbeat.relocate_partition_to_tablespace('heartbeat', part_name, 'ts_hot');
END;
$$;