获取分区 table 的 table 大小(Postgres 10+)
Get table size of partitioned table (Postgres 10+)
我在 Postgres weekly 上遇到了这个查询,它以字节为单位显示了 tables、它们的大小、toast 大小和索引大小:
SELECT
relname AS table_name,
pg_size_pretty(pg_total_relation_size(relid)) AS total,
pg_size_pretty(pg_relation_size(relid)) AS internal,
pg_size_pretty(pg_table_size(relid) - pg_relation_size(relid)) AS external,
pg_size_pretty(pg_indexes_size(relid)) AS indexes
FROM pg_catalog.pg_statio_user_tables
ORDER BY pg_total_relation_size(relid) DESC;
我知道 Postgres 正在为每个分区创建一个 table,所以我分别为每个分区获取条目,但是有没有办法为每个 table 获取一行,而不管这是否table是否分区?
当然可以,但是您必须加入一堆其他目录 table 并使用 GROUP BY
。
目录 pg_class
中的属性 relkind
将告诉您关系是否已分区 (p
) 或未分区 (r
)。
目录pg_inherits
会告诉你哪个分区(inhrelid
)属于哪个分区table(inhparent
).
因为分区可以再分区,所以要覆盖所有的基就得写一个递归的通用table表达式
按照@Laurenz Albe 的说明,我创建了一个满足我需求的查询。这将从特定数据库中获取所有分区 table 的总内存。
SELECT
pi.inhparent::regclass AS parent_table_name,
pg_size_pretty(sum(pg_total_relation_size(psu.relid))) AS total,
pg_size_pretty(sum(pg_relation_size(psu.relid))) AS internal,
pg_size_pretty(sum(pg_table_size(psu.relid) - pg_relation_size(psu.relid))) AS external, -- toast
pg_size_pretty(sum(pg_indexes_size(psu.relid))) AS indexes
FROM pg_catalog.pg_statio_user_tables psu
JOIN pg_class pc ON psu.relname = pc.relname
JOIN pg_database pd ON pc.relowner = pd.datdba
JOIN pg_inherits pi ON pi.inhrelid = pc.oid
WHERE pd.datname = :database_name
GROUP BY pi.inhparent
ORDER BY sum(pg_total_relation_size(psu.relid)) DESC;
请注意,在我们有多个分区的情况下,根 table 不会有一行,但每个父 table 都会有自己的行
即使我们有多个分区级别,这也会为每个父级 table 提供 table 大小:
WITH RECURSIVE tables AS (
SELECT
c.oid AS parent,
c.oid AS relid,
1 AS level
FROM pg_catalog.pg_class c
LEFT JOIN pg_catalog.pg_inherits AS i ON c.oid = i.inhrelid
-- p = partitioned table, r = normal table
WHERE c.relkind IN ('p', 'r')
-- not having a parent table -> we only get the partition heads
AND i.inhrelid IS NULL
UNION ALL
SELECT
p.parent AS parent,
c.oid AS relid,
p.level + 1 AS level
FROM tables AS p
LEFT JOIN pg_catalog.pg_inherits AS i ON p.relid = i.inhparent
LEFT JOIN pg_catalog.pg_class AS c ON c.oid = i.inhrelid AND c.relispartition
WHERE c.oid IS NOT NULL
)
SELECT
parent ::REGCLASS AS table_name,
array_agg(relid :: REGCLASS) AS all_partitions,
pg_size_pretty(sum(pg_total_relation_size(relid))) AS pretty_total_size,
sum(pg_total_relation_size(relid)) AS total_size
FROM tables
GROUP BY parent
ORDER BY sum(pg_total_relation_size(relid)) DESC
我在 Postgres weekly 上遇到了这个查询,它以字节为单位显示了 tables、它们的大小、toast 大小和索引大小:
SELECT
relname AS table_name,
pg_size_pretty(pg_total_relation_size(relid)) AS total,
pg_size_pretty(pg_relation_size(relid)) AS internal,
pg_size_pretty(pg_table_size(relid) - pg_relation_size(relid)) AS external,
pg_size_pretty(pg_indexes_size(relid)) AS indexes
FROM pg_catalog.pg_statio_user_tables
ORDER BY pg_total_relation_size(relid) DESC;
我知道 Postgres 正在为每个分区创建一个 table,所以我分别为每个分区获取条目,但是有没有办法为每个 table 获取一行,而不管这是否table是否分区?
当然可以,但是您必须加入一堆其他目录 table 并使用 GROUP BY
。
目录
pg_class
中的属性relkind
将告诉您关系是否已分区 (p
) 或未分区 (r
)。目录
pg_inherits
会告诉你哪个分区(inhrelid
)属于哪个分区table(inhparent
).
因为分区可以再分区,所以要覆盖所有的基就得写一个递归的通用table表达式
按照@Laurenz Albe 的说明,我创建了一个满足我需求的查询。这将从特定数据库中获取所有分区 table 的总内存。
SELECT
pi.inhparent::regclass AS parent_table_name,
pg_size_pretty(sum(pg_total_relation_size(psu.relid))) AS total,
pg_size_pretty(sum(pg_relation_size(psu.relid))) AS internal,
pg_size_pretty(sum(pg_table_size(psu.relid) - pg_relation_size(psu.relid))) AS external, -- toast
pg_size_pretty(sum(pg_indexes_size(psu.relid))) AS indexes
FROM pg_catalog.pg_statio_user_tables psu
JOIN pg_class pc ON psu.relname = pc.relname
JOIN pg_database pd ON pc.relowner = pd.datdba
JOIN pg_inherits pi ON pi.inhrelid = pc.oid
WHERE pd.datname = :database_name
GROUP BY pi.inhparent
ORDER BY sum(pg_total_relation_size(psu.relid)) DESC;
请注意,在我们有多个分区的情况下,根 table 不会有一行,但每个父 table 都会有自己的行
即使我们有多个分区级别,这也会为每个父级 table 提供 table 大小:
WITH RECURSIVE tables AS (
SELECT
c.oid AS parent,
c.oid AS relid,
1 AS level
FROM pg_catalog.pg_class c
LEFT JOIN pg_catalog.pg_inherits AS i ON c.oid = i.inhrelid
-- p = partitioned table, r = normal table
WHERE c.relkind IN ('p', 'r')
-- not having a parent table -> we only get the partition heads
AND i.inhrelid IS NULL
UNION ALL
SELECT
p.parent AS parent,
c.oid AS relid,
p.level + 1 AS level
FROM tables AS p
LEFT JOIN pg_catalog.pg_inherits AS i ON p.relid = i.inhparent
LEFT JOIN pg_catalog.pg_class AS c ON c.oid = i.inhrelid AND c.relispartition
WHERE c.oid IS NOT NULL
)
SELECT
parent ::REGCLASS AS table_name,
array_agg(relid :: REGCLASS) AS all_partitions,
pg_size_pretty(sum(pg_total_relation_size(relid))) AS pretty_total_size,
sum(pg_total_relation_size(relid)) AS total_size
FROM tables
GROUP BY parent
ORDER BY sum(pg_total_relation_size(relid)) DESC