Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Select an option

  • Save MichaelLeeHobbs/be3b5a8972ccebf8217c4f1088e79467 to your computer and use it in GitHub Desktop.

Select an option

Save MichaelLeeHobbs/be3b5a8972ccebf8217c4f1088e79467 to your computer and use it in GitHub Desktop.
Mirth 4.5.0 Table Size Reports
WITH
-- 1. EXTRACT CONFIGURATION
CHANNEL_CONFIG AS (
SELECT
(XPATH('/entry/string/text()', ENTRY))[1]::TEXT AS CID
, (XPATH('/entry/*[2]/enabled/text()', ENTRY))[1]::TEXT::BOOLEAN AS CHANNEL_ENABLED
, (XPATH('/entry/*[2]/pruningSettings/archiveEnabled/text()', ENTRY))[1]::TEXT::BOOLEAN AS ARCHIVE_ENABLED
, (XPATH('/entry/*[2]/pruningSettings/pruneErroredMessages/text()', ENTRY))[1]::TEXT::BOOLEAN AS PRUNE_ERROR_MESSAGES
, COALESCE((XPATH('/entry/*[2]/pruningSettings/pruneMetaDataDays/text()', ENTRY))[1]::TEXT::INT, -1) AS PRUNE_DAYS
FROM (
SELECT UNNEST(XPATH('/map/entry', VALUE::XML)) AS ENTRY
FROM CONFIGURATION
WHERE CATEGORY = 'core' AND NAME = 'channelMetadata'
) X
),
-- 2. GET OLDEST DATE ESTIMATES FROM PG_STATS (Instant, no table scans)
DATE_ESTIMATES AS (
SELECT
tablename
-- Extract the first element of the histogram array (Approx Min Date)
, (histogram_bounds::TEXT::TIMESTAMP WITHOUT TIME ZONE[])[1] AS OLDEST_MSG_DATE
FROM pg_stats
WHERE schemaname = 'public'
AND attname = 'received_date'
-- We only care about the main message tables (d_m1, d_m2, etc)
AND tablename ~ '^d_m\d+$'
),
-- 3. CALCULATE RAW TABLE SIZES
RECURSIVE_INHERIT AS (
WITH RECURSIVE PG_INHERIT(INHRELID, INHPARENT) AS (
SELECT INHRELID, INHPARENT FROM PG_INHERITS
UNION
SELECT CHILD.INHRELID, PARENT.INHPARENT
FROM PG_INHERIT CHILD, PG_INHERITS PARENT
WHERE CHILD.INHPARENT = PARENT.INHRELID
)
SELECT * FROM PG_INHERIT
),
TABLE_STATS AS (
SELECT
NSPNAME AS TABLE_SCHEMA
, RELNAME AS TABLE_NAME
, C.OID AS TABLE_OID
, COALESCE(I.INHPARENT, C.OID) AS PARENT_OID
, C.RELTUPLES
, PG_TOTAL_RELATION_SIZE(C.OID) AS TOTAL_BYTES_RAW
, PG_INDEXES_SIZE(C.OID) AS INDEX_BYTES_RAW
, PG_TOTAL_RELATION_SIZE(RELTOASTRELID) AS TOAST_BYTES_RAW
FROM PG_CLASS C
LEFT JOIN PG_NAMESPACE N ON N.OID = C.RELNAMESPACE
LEFT JOIN RECURSIVE_INHERIT I ON I.INHRELID = C.OID
WHERE RELKIND IN ('r', 'p')
),
AGGREGATED_SIZES AS (
SELECT
TABLE_SCHEMA
, TABLE_NAME
, SUM(RELTUPLES) OVER (PARTITION BY PARENT_OID) AS ROW_ESTIMATE
, SUM(TOTAL_BYTES_RAW) OVER (PARTITION BY PARENT_OID) AS TOTAL_BYTES
, SUM(INDEX_BYTES_RAW) OVER (PARTITION BY PARENT_OID) AS INDEX_BYTES
, SUM(TOAST_BYTES_RAW) OVER (PARTITION BY PARENT_OID) AS TOAST_BYTES
, PARENT_OID
, TABLE_OID
FROM TABLE_STATS
),
-- 4. FLATTEN DATA
FLATTENED_DATA AS (
SELECT
COALESCE(CHANNEL.NAME, 'Unknown/System') AS CHANNEL_NAME
, D.CHANNEL_ID
, M.CHANNEL_ENABLED
, M.PRUNE_DAYS
, M.PRUNE_ERROR_MESSAGES
, M.ARCHIVE_ENABLED
, S.TABLE_NAME
, S.MIRTH_TYPE
, S.TOTAL_BYTES
, S.TABLE_BYTES
, S.INDEX_BYTES
, S.ROW_ESTIMATE
, S.MIRTH_ID
FROM (
SELECT DISTINCT ON (PARENT_OID)
TABLE_SCHEMA
, TABLE_NAME
, NULLIF(REGEXP_REPLACE(TABLE_NAME, '\D', '', 'g'), '')::NUMERIC AS MIRTH_ID
, SUBSTRING(TABLE_NAME FROM 'd_(\D+)\d+') AS MIRTH_TYPE
, ROW_ESTIMATE
, TOTAL_BYTES
, INDEX_BYTES
, TOAST_BYTES
, (TOTAL_BYTES - INDEX_BYTES - COALESCE(TOAST_BYTES, 0)) AS TABLE_BYTES
FROM AGGREGATED_SIZES
WHERE TABLE_OID = PARENT_OID
) S
LEFT JOIN D_CHANNELS D ON D.LOCAL_CHANNEL_ID = S.MIRTH_ID
LEFT JOIN CHANNEL ON CHANNEL.ID = D.CHANNEL_ID
LEFT JOIN CHANNEL_CONFIG M ON M.CID = D.CHANNEL_ID
WHERE S.MIRTH_ID IS NOT NULL
)
-- 5. FINAL REPORT
SELECT
F.CHANNEL_NAME
, F.CHANNEL_ENABLED
, F.PRUNE_DAYS
, F.PRUNE_ERROR_MESSAGES
-- PRUNING HEALTH CHECK
, CASE
WHEN F.PRUNE_DAYS = -1 THEN 'N/A'
WHEN DE.OLDEST_MSG_DATE < (NOW() - (F.PRUNE_DAYS + 1 || ' days')::INTERVAL) THEN 'BACKLOG OR UNPRUNED ERRORS DETECTED'
ELSE 'OK'
END AS PRUNE_STATUS
, TO_CHAR(DE.OLDEST_MSG_DATE, 'YYYY-MM-DD HH24:MI') AS OLDEST_MSG_EST
-- SIZES
, PG_SIZE_PRETTY(SUM(F.TOTAL_BYTES)) AS TOTAL_CHANNEL_SIZE
, SUM(F.ROW_ESTIMATE)::BIGINT AS TOTAL_MSG_ESTIMATE
-- DETAILS JSON
, JSONB_AGG(
JSONB_BUILD_OBJECT(
'type', COALESCE(F.MIRTH_TYPE, 'msg'),
'table', F.TABLE_NAME,
'size', PG_SIZE_PRETTY(F.TOTAL_BYTES),
'rows', F.ROW_ESTIMATE::BIGINT
) ORDER BY F.TOTAL_BYTES DESC
) AS TABLE_DETAILS
, SUM(F.TOTAL_BYTES) AS _SORT_BYTES
FROM FLATTENED_DATA F
-- Join to Date Estimates based on the main message table name (d_m + local_channel_id)
LEFT JOIN DATE_ESTIMATES DE ON DE.tablename = ('d_m' || F.MIRTH_ID)
GROUP BY
F.CHANNEL_NAME
, F.CHANNEL_ID
, F.CHANNEL_ENABLED
, F.PRUNE_DAYS
, F.PRUNE_ERROR_MESSAGES
, F.ARCHIVE_ENABLED
, DE.OLDEST_MSG_DATE
ORDER BY _SORT_BYTES DESC;
WITH
-- 1. EXTRACT CONFIGURATION FIRST
CHANNEL_CONFIG AS (
SELECT
(XPATH('/entry/string/text()', ENTRY))[1]::TEXT AS CID
, (XPATH('/entry/*[2]/enabled/text()', ENTRY))[1]::TEXT::BOOLEAN AS CHANNEL_ENABLED
, (XPATH('/entry/*[2]/pruningSettings/archiveEnabled/text()', ENTRY))[1]::TEXT::BOOLEAN AS ARCHIVE_ENABLED
, (XPATH('/entry/*[2]/pruningSettings/pruneErroredMessages/text()', ENTRY))[1]::TEXT::BOOLEAN AS PRUNE_ERROR_MESSAGES
-- Coalesce NULL to -1 to indicate "Not Set/Default"
, COALESCE((XPATH('/entry/*[2]/pruningSettings/pruneMetaDataDays/text()', ENTRY))[1]::TEXT::INT, -1) AS PRUNE_DAYS
FROM (
SELECT UNNEST(XPATH('/map/entry', VALUE::XML)) AS ENTRY
FROM CONFIGURATION
WHERE CATEGORY = 'core' AND NAME = 'channelMetadata'
) X
),
-- 2. CALCULATE TABLE SIZES
RECURSIVE_INHERIT AS (
WITH RECURSIVE PG_INHERIT(INHRELID, INHPARENT) AS (
SELECT INHRELID, INHPARENT FROM PG_INHERITS
UNION
SELECT CHILD.INHRELID, PARENT.INHPARENT
FROM PG_INHERIT CHILD, PG_INHERITS PARENT
WHERE CHILD.INHPARENT = PARENT.INHRELID
)
SELECT * FROM PG_INHERIT
),
TABLE_STATS AS (
SELECT
NSPNAME AS TABLE_SCHEMA
, RELNAME AS TABLE_NAME
, C.OID AS TABLE_OID
, COALESCE(I.INHPARENT, C.OID) AS PARENT_OID
, C.RELTUPLES
, PG_TOTAL_RELATION_SIZE(C.OID) AS TOTAL_BYTES_RAW
, PG_INDEXES_SIZE(C.OID) AS INDEX_BYTES_RAW
, PG_TOTAL_RELATION_SIZE(RELTOASTRELID) AS TOAST_BYTES_RAW
FROM PG_CLASS C
LEFT JOIN PG_NAMESPACE N ON N.OID = C.RELNAMESPACE
LEFT JOIN RECURSIVE_INHERIT I ON I.INHRELID = C.OID
WHERE RELKIND IN ('r', 'p')
),
AGGREGATED_SIZES AS (
SELECT
TABLE_SCHEMA
, TABLE_NAME
, SUM(RELTUPLES) OVER (PARTITION BY PARENT_OID) AS ROW_ESTIMATE
, SUM(TOTAL_BYTES_RAW) OVER (PARTITION BY PARENT_OID) AS TOTAL_BYTES
, SUM(INDEX_BYTES_RAW) OVER (PARTITION BY PARENT_OID) AS INDEX_BYTES
, SUM(TOAST_BYTES_RAW) OVER (PARTITION BY PARENT_OID) AS TOAST_BYTES
, PARENT_OID
, TABLE_OID
FROM TABLE_STATS
)
-- 3. MAIN REPORT
SELECT
COALESCE(CHANNEL.NAME, 'Unknown/System') AS CHANNEL_NAME
, M.CHANNEL_ENABLED
, M.PRUNE_DAYS
, M.PRUNE_ERROR_MESSAGES
, M.ARCHIVE_ENABLED
, S.TABLE_NAME
, S.MIRTH_TYPE
, PG_SIZE_PRETTY(S.TOTAL_BYTES) AS TOTAL_SIZE_PRETTY
, PG_SIZE_PRETTY(S.TABLE_BYTES) AS DATA_SIZE_PRETTY
, PG_SIZE_PRETTY(S.INDEX_BYTES) AS INDEX_SIZE_PRETTY
, S.ROW_ESTIMATE::BIGINT AS ROW_ESTIMATE
-- Raw bytes included for sorting in SQL clients
, S.TOTAL_BYTES AS _SORT_TOTAL_BYTES
FROM (
SELECT DISTINCT ON (PARENT_OID)
TABLE_SCHEMA
, TABLE_NAME
, NULLIF(REGEXP_REPLACE(TABLE_NAME, '\D', '', 'g'), '')::NUMERIC AS MIRTH_ID
, SUBSTRING(TABLE_NAME FROM 'd_(\D+)\d+') AS MIRTH_TYPE
, ROW_ESTIMATE
, TOTAL_BYTES
, INDEX_BYTES
, TOAST_BYTES
, (TOTAL_BYTES - INDEX_BYTES - COALESCE(TOAST_BYTES, 0)) AS TABLE_BYTES
FROM AGGREGATED_SIZES
WHERE TABLE_OID = PARENT_OID -- Only get the parent/summary rows
) S
LEFT JOIN D_CHANNELS D ON D.LOCAL_CHANNEL_ID = S.MIRTH_ID
LEFT JOIN CHANNEL ON CHANNEL.ID = D.CHANNEL_ID
LEFT JOIN CHANNEL_CONFIG M ON M.CID = D.CHANNEL_ID
WHERE S.MIRTH_ID IS NOT NULL -- Filter out non-Mirth tables
ORDER BY S.TOTAL_BYTES DESC;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment