Enhance partitioning logic and update Zabbix config template
This commit is contained in:
@@ -8,7 +8,7 @@ CREATE SCHEMA IF NOT EXISTS partitions;
|
|||||||
-- Configuration table to store partitioning settings per table
|
-- Configuration table to store partitioning settings per table
|
||||||
CREATE TABLE IF NOT EXISTS partitions.config (
|
CREATE TABLE IF NOT EXISTS partitions.config (
|
||||||
table_name text NOT NULL,
|
table_name text NOT NULL,
|
||||||
period text NOT NULL CHECK (period IN ('day', 'week', 'month', 'year')),
|
period text NOT NULL,
|
||||||
keep_history interval NOT NULL,
|
keep_history interval NOT NULL,
|
||||||
future_partitions integer NOT NULL DEFAULT 5,
|
future_partitions integer NOT NULL DEFAULT 5,
|
||||||
last_updated timestamp WITH TIME ZONE DEFAULT (now() AT TIME ZONE 'UTC'),
|
last_updated timestamp WITH TIME ZONE DEFAULT (now() AT TIME ZONE 'UTC'),
|
||||||
|
|||||||
@@ -43,6 +43,8 @@ BEGIN
|
|||||||
|
|
||||||
IF p_period = 'month' THEN
|
IF p_period = 'month' THEN
|
||||||
v_suffix := to_char(p_start_time, 'YYYYMM');
|
v_suffix := to_char(p_start_time, 'YYYYMM');
|
||||||
|
ELSIF p_period LIKE '%hour%' THEN
|
||||||
|
v_suffix := to_char(p_start_time, 'YYYYMMDDHH24');
|
||||||
ELSE
|
ELSE
|
||||||
v_suffix := to_char(p_start_time, 'YYYYMMDD');
|
v_suffix := to_char(p_start_time, 'YYYYMMDD');
|
||||||
END IF;
|
END IF;
|
||||||
@@ -91,26 +93,47 @@ BEGIN
|
|||||||
BEGIN
|
BEGIN
|
||||||
IF length(v_suffix) = 6 THEN -- YYYYMM
|
IF length(v_suffix) = 6 THEN -- YYYYMM
|
||||||
v_partition_date := to_timestamp(v_suffix || '01', 'YYYYMMDD') AT TIME ZONE 'UTC';
|
v_partition_date := to_timestamp(v_suffix || '01', 'YYYYMMDD') AT TIME ZONE 'UTC';
|
||||||
-- For monthly, we check if the END of the month is older than retention?
|
ELSIF length(v_suffix) = 8 THEN -- YYYYMMDD
|
||||||
-- Or just strict retention.
|
v_partition_date := to_timestamp(v_suffix, 'YYYYMMDD') AT TIME ZONE 'UTC';
|
||||||
-- To be safe, adding 1 month to check vs cutoff.
|
ELSIF length(v_suffix) = 10 THEN -- YYYYMMDDHH
|
||||||
IF extract(epoch from (v_partition_date + '1 month'::interval)) < v_cutoff_ts THEN
|
v_partition_date := to_timestamp(v_suffix, 'YYYYMMDDHH24') AT TIME ZONE 'UTC';
|
||||||
|
ELSE
|
||||||
|
CONTINUE; -- Ignore non-matching suffix lengths
|
||||||
|
END IF;
|
||||||
|
EXCEPTION WHEN OTHERS THEN
|
||||||
|
-- Safely ignore parsing errors for oddly named partitions
|
||||||
|
CONTINUE;
|
||||||
|
END;
|
||||||
|
|
||||||
|
-- Now check retention and execute DROP TABLE (so dropping errors are correctly raised!)
|
||||||
|
IF length(v_suffix) = 6 THEN -- YYYYMM
|
||||||
|
IF extract(epoch from (v_partition_date + '1 month'::interval)) < v_cutoff_ts THEN
|
||||||
|
RAISE NOTICE 'Dropping old partition %', v_partition.partition_name;
|
||||||
|
EXECUTE format('DROP TABLE %I.%I', v_partition.partition_schema, v_partition.partition_name);
|
||||||
|
COMMIT; -- Release lock immediately
|
||||||
|
END IF;
|
||||||
|
ELSIF length(v_suffix) = 8 THEN -- YYYYMMDD
|
||||||
|
-- If period is weekly, the partition spans an entire week. Otherwise, it spans one day.
|
||||||
|
IF p_period = 'week' THEN
|
||||||
|
IF extract(epoch from (v_partition_date + '1 week'::interval)) < v_cutoff_ts THEN
|
||||||
RAISE NOTICE 'Dropping old partition %', v_partition.partition_name;
|
RAISE NOTICE 'Dropping old partition %', v_partition.partition_name;
|
||||||
EXECUTE format('DROP TABLE %I.%I', v_partition.partition_schema, v_partition.partition_name);
|
EXECUTE format('DROP TABLE %I.%I', v_partition.partition_schema, v_partition.partition_name);
|
||||||
COMMIT; -- Release lock immediately
|
COMMIT; -- Release lock immediately
|
||||||
END IF;
|
END IF;
|
||||||
ELSIF length(v_suffix) = 8 THEN -- YYYYMMDD
|
ELSE
|
||||||
v_partition_date := to_timestamp(v_suffix, 'YYYYMMDD') AT TIME ZONE 'UTC';
|
|
||||||
IF extract(epoch from (v_partition_date + '1 day'::interval)) < v_cutoff_ts THEN
|
IF extract(epoch from (v_partition_date + '1 day'::interval)) < v_cutoff_ts THEN
|
||||||
RAISE NOTICE 'Dropping old partition %', v_partition.partition_name;
|
RAISE NOTICE 'Dropping old partition %', v_partition.partition_name;
|
||||||
EXECUTE format('DROP TABLE %I.%I', v_partition.partition_schema, v_partition.partition_name);
|
EXECUTE format('DROP TABLE %I.%I', v_partition.partition_schema, v_partition.partition_name);
|
||||||
COMMIT; -- Release lock immediately
|
COMMIT; -- Release lock immediately
|
||||||
END IF;
|
END IF;
|
||||||
END IF;
|
END IF;
|
||||||
EXCEPTION WHEN OTHERS THEN
|
ELSIF length(v_suffix) = 10 THEN -- YYYYMMDDHH
|
||||||
-- Ignore parsing errors for non-standard partitions
|
IF extract(epoch from (v_partition_date + p_period::interval)) < v_cutoff_ts THEN
|
||||||
NULL;
|
RAISE NOTICE 'Dropping old partition %', v_partition.partition_name;
|
||||||
END;
|
EXECUTE format('DROP TABLE %I.%I', v_partition.partition_schema, v_partition.partition_name);
|
||||||
|
COMMIT; -- Release lock immediately
|
||||||
|
END IF;
|
||||||
|
END IF;
|
||||||
END LOOP;
|
END LOOP;
|
||||||
END;
|
END;
|
||||||
$$;
|
$$;
|
||||||
@@ -145,8 +168,14 @@ BEGIN
|
|||||||
v_start_time := date_trunc('month', now() AT TIME ZONE 'UTC');
|
v_start_time := date_trunc('month', now() AT TIME ZONE 'UTC');
|
||||||
-- Approximate 30 days per month (2592000 seconds)
|
-- Approximate 30 days per month (2592000 seconds)
|
||||||
v_past_iterations := ceil(extract(epoch from p_keep_history) / 2592000)::integer;
|
v_past_iterations := ceil(extract(epoch from p_keep_history) / 2592000)::integer;
|
||||||
|
|
||||||
|
ELSIF p_period LIKE '%hour%' THEN
|
||||||
|
v_period_interval := p_period::interval;
|
||||||
|
v_start_time := date_trunc('hour', now() AT TIME ZONE 'UTC');
|
||||||
|
v_past_iterations := ceil(extract(epoch from p_keep_history) / extract(epoch from v_period_interval))::integer;
|
||||||
|
|
||||||
ELSE
|
ELSE
|
||||||
RETURN;
|
RAISE EXCEPTION 'Unsupported partitioning period: %', p_period;
|
||||||
END IF;
|
END IF;
|
||||||
|
|
||||||
-- 1. Create Future Partitions (Current + Buffer)
|
-- 1. Create Future Partitions (Current + Buffer)
|
||||||
|
|||||||
@@ -12,9 +12,13 @@ SELECT
|
|||||||
count(child.relname) AS partition_count,
|
count(child.relname) AS partition_count,
|
||||||
count(child.relname) FILTER (
|
count(child.relname) FILTER (
|
||||||
WHERE
|
WHERE
|
||||||
(c.period = 'day' AND child.relname > (parent.relname || '_p' || to_char(now(), 'YYYYMMDD')))
|
(c.period = 'day' AND child.relname > (parent.relname || '_p' || to_char(now() AT TIME ZONE 'UTC', 'YYYYMMDD')))
|
||||||
OR
|
OR
|
||||||
(c.period = 'month' AND child.relname > (parent.relname || '_p' || to_char(now(), 'YYYYMM')))
|
(c.period = 'month' AND child.relname > (parent.relname || '_p' || to_char(now() AT TIME ZONE 'UTC', 'YYYYMM')))
|
||||||
|
OR
|
||||||
|
(c.period = 'week' AND child.relname > (parent.relname || '_p' || to_char(date_trunc('week', now() AT TIME ZONE 'UTC'), 'YYYYMMDD')))
|
||||||
|
OR
|
||||||
|
(c.period LIKE '%hour%' AND child.relname > (parent.relname || '_p' || to_char(now() AT TIME ZONE 'UTC', 'YYYYMMDDHH24')))
|
||||||
) AS future_partitions,
|
) AS future_partitions,
|
||||||
sum(pg_total_relation_size(child.oid)) AS total_size_bytes,
|
sum(pg_total_relation_size(child.oid)) AS total_size_bytes,
|
||||||
pg_size_pretty(sum(pg_total_relation_size(child.oid))) AS total_size,
|
pg_size_pretty(sum(pg_total_relation_size(child.oid))) AS total_size,
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
SELECT
|
SELECT
|
||||||
table_name,
|
table_name,
|
||||||
|
period,
|
||||||
|
keep_history::text AS keep_history,
|
||||||
future_partitions,
|
future_partitions,
|
||||||
total_size_bytes,
|
total_size_bytes,
|
||||||
EXTRACT(EPOCH FROM (now() - last_updated)) AS age_seconds
|
EXTRACT(EPOCH FROM (now() - last_updated)) AS age_seconds
|
||||||
|
|||||||
@@ -86,6 +86,38 @@ zabbix_export:
|
|||||||
value: size
|
value: size
|
||||||
- tag: table
|
- tag: table
|
||||||
value: '{#TABLE_NAME}'
|
value: '{#TABLE_NAME}'
|
||||||
|
- uuid: ffa2b3c4d5e64f7a9b8c7d6e5f4a1001
|
||||||
|
name: '{#TABLE_NAME}: Configured Partition Period'
|
||||||
|
type: DEPENDENT
|
||||||
|
key: 'db.partitions.period["{#TABLE_NAME}"]'
|
||||||
|
value_type: CHAR
|
||||||
|
preprocessing:
|
||||||
|
- type: JSONPATH
|
||||||
|
parameters:
|
||||||
|
- '$.[?(@.table_name == "{#TABLE_NAME}")].period.first()'
|
||||||
|
master_item:
|
||||||
|
key: 'pgsql.custom.query["{$PG.CONNSTRING.AGENT2}",,,"{$PG.DBNAME}","partitions.get_all"]'
|
||||||
|
tags:
|
||||||
|
- tag: metric
|
||||||
|
value: config
|
||||||
|
- tag: table
|
||||||
|
value: '{#TABLE_NAME}'
|
||||||
|
- uuid: ffa2b3c4d5e64f7a9b8c7d6e5f4a1002
|
||||||
|
name: '{#TABLE_NAME}: Configured Retention (Keep History)'
|
||||||
|
type: DEPENDENT
|
||||||
|
key: 'db.partitions.retention["{#TABLE_NAME}"]'
|
||||||
|
value_type: CHAR
|
||||||
|
preprocessing:
|
||||||
|
- type: JSONPATH
|
||||||
|
parameters:
|
||||||
|
- '$.[?(@.table_name == "{#TABLE_NAME}")].keep_history.first()'
|
||||||
|
master_item:
|
||||||
|
key: 'pgsql.custom.query["{$PG.CONNSTRING.AGENT2}",,,"{$PG.DBNAME}","partitions.get_all"]'
|
||||||
|
tags:
|
||||||
|
- tag: metric
|
||||||
|
value: config
|
||||||
|
- tag: table
|
||||||
|
value: '{#TABLE_NAME}'
|
||||||
master_item:
|
master_item:
|
||||||
key: 'pgsql.custom.query["{$PG.CONNSTRING.AGENT2}",,,"{$PG.DBNAME}","partitions.get_all"]'
|
key: 'pgsql.custom.query["{$PG.CONNSTRING.AGENT2}",,,"{$PG.DBNAME}","partitions.get_all"]'
|
||||||
lld_macro_paths:
|
lld_macro_paths:
|
||||||
|
|||||||
Reference in New Issue
Block a user