You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PostgreSQL 12.8继承表场景如何快速获取总行数

PostgreSQL 12.8 继承+分区架构下60秒内完成总行数统计方案

你当前的架构(单基表挂载200张继承子表、每子表下设5个分区,合计约1000张物理表,总数据量20CR)直接执行SELECT count(*) FROM 基表耗时过长,核心原因是数据库需要递归遍历整个继承+分区树,逐表扫描可见性映射判断行可见性,元数据遍历+数据扫描的总开销很容易超出阈值。以下方案均可在60秒内完成统计,按精度从高到低排列:

方案1:精确统计(常规场景下10-40秒完成)

通过跳过继承递归元数据校验+开启并行查询优化,直接统计所有物理表行数后汇总,结果100%准确:

  • 先在当前会话调整并行参数,充分利用多核算力(参数根据服务器CPU核数调整,不需要重启数据库,会话退出后自动失效):
SET max_parallel_workers_per_gather = 16; -- 建议设置为物理CPU核数的1/2~2/3
SET parallel_setup_cost = 10;
SET parallel_tuple_cost = 0.01;
SET enable_parallel_append = on; -- PG12默认开启,确认未被全局配置关闭
  • 通过系统表自动拼接所有关联物理表的统计SQL,避免直接查基表触发的继承递归校验开销:
-- 执行该语句会生成最终的count统计SQL,替换语句内的基表名、schema名后运行即可
SELECT format(
  'SELECT sum(row_count)::bigint AS total_rows FROM (%s) t',
  string_agg(
    format('SELECT count(*) AS row_count FROM %I.%I', nspname, relname),
    ' UNION ALL '
  )
)
FROM (
  WITH RECURSIVE all_rel AS (
    SELECT oid, relname, relnamespace
    FROM pg_class
    WHERE relname = '替换为你的基表名'
      AND relnamespace = '替换为基表所在schema'::regnamespace -- 比如public
    UNION ALL
    SELECT c.oid, c.relname, c.relnamespace
    FROM pg_inherits i
    JOIN pg_class c ON i.inhrelid = c.oid
    JOIN all_rel ar ON i.inhparent = ar.oid
  )
  SELECT c.relname, n.nspname
  FROM all_rel c
  JOIN pg_namespace n ON c.relnamespace = n.oid
) rels;

只要存储IO不是瓶颈,该方案在16核服务器上跑20CR数据基本能稳定在40秒以内。

方案2:毫秒级近似统计(误差通常<1%,适合非强精度要求场景)

直接读取数据库统计信息表中存储的行数估算值,不需要扫描实际业务数据,几毫秒就能出结果:

-- 替换语句内的基表名、schema名后直接执行
SELECT sum(c.reltuples)::bigint AS approx_total_rows
FROM pg_class c
WHERE c.oid IN (
  WITH RECURSIVE all_rel AS (
    SELECT oid FROM pg_class
    WHERE relname = '替换为你的基表名'
      AND relnamespace = '替换为基表所在schema'::regnamespace
    UNION ALL
    SELECT i.inhrelid
    FROM pg_inherits i
    JOIN all_rel ar ON i.inhparent = ar.oid
  )
  SELECT oid FROM all_rel
);

注意:该数值是autovacuum后台进程上次统计时的表行数,如果近期有大批量写入、删除操作,误差会有所升高。可以在统计前执行ANALYZE 基表名;手动触发统计信息更新(仅更新统计信息不清理死元组,IO开销极低,20CR规模的表数分钟即可完成全部分区的统计更新),更新后误差可控制在0.1%以内。

方案3:毫秒级精确统计(适合高频统计需求)

如果需要频繁获取精确总行数,不要每次临时扫描全表,通过触发器维护独立的行数计数表即可:

  • 首先创建行数统计元表:
CREATE TABLE table_row_counter (
  table_oid oid PRIMARY KEY,
  table_full_name text,
  row_count bigint NOT NULL DEFAULT 0
);
  • 初始化时先跑一次全量count,把所有关联表的基准行数写入该元表。
  • 给所有继承子表、分区表批量创建行级触发器:表发生插入操作时对应计数+1,删除操作时对应计数-1,截断操作时直接将对应表计数置0。

初始化完成后,后续查询直接对元表的row_count字段求和即可,结果100%准确,查询耗时几毫秒。触发器的额外写入开销极低,单表TPS在1万以内的场景几乎感知不到性能影响。

内容的提问来源于stack exchange,提问作者CoderAkki

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.31 21:12:13