【问题标题】:Get table size of partitioned table (Postgres 10+)获取分区表的表大小(Postgres 10+)
【发布时间】:2019-02-28 07:56:40
【问题描述】:

我在Postgres weekly 上遇到了这个查询,它显示了表格、它们的大小、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 正在为每个分区创建一个表,因此我分别获取每个分区的条目,但是有没有办法让每个表获得一行,无论该表是否分区?

【问题讨论】:

    标签: postgresql postgresql-10 postgresql-11 postgres-12


    【解决方案1】:

    按照@Laurenz Albe 的指示,我创建了一个满足我需求的查询。这将从特定数据库中获取所有分区表的总内存。

    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;
    

    请注意,如果我们有分区的分区,根表不会有一行,但每个父表都有自己的行

    【讨论】:

    • 实际上每个分区只需要一行。替换 pi.inhparent 在 group by 和 pi.inhparent::regclass AS parent_table_name 在 select 与 psu.relname 获胜。
    【解决方案2】:

    即使我们有多个分区级别,这也会给出每个父表的表大小:

    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
    

    【讨论】:

      【解决方案3】:

      当然可以,但是您必须加入一堆其他目录表并使用GROUP BY

      • 目录pg_class 中的属性relkind 将告诉您关系是否已分区(p)或未分区(r)。

      • 目录pg_inherits 会告诉您哪个分区 (inhrelid) 属于哪个分区表 (inhparent)。

      由于分区可以再次分区,如果要覆盖所有基,则必须编写递归公用表表达式。

      【讨论】:

        猜你喜欢
        • 2014-03-14
        • 1970-01-01
        • 1970-01-01
        • 2022-11-23
        • 1970-01-01
        • 2020-06-05
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多