跳至内容
附录 D 分区能力索引

附录 D:分区能力索引

分区不是一个孤立功能:是否该用、查询能否裁剪、如何在线迁移、时间边界怎样表达、 旧分区如何冻结/退役,分布在五个章节。本附录把它们串成一条生命周期。

D.1 ch04:分区决策门

ch04.6 先问:

dominant lifecycle boundary?
queries usually constrain the same key?
retention/archive needs cheap detach/drop?
maintenance can benefit from smaller independent relations?
number and creation rate of partitions remain bounded?

不要因为“表会变大”自动分区。分区会增加:

  • parent/child catalog、DDL、statistics 与 plan 开销;
  • partition creation/retention automation;
  • constraint/unique/FK 设计限制;
  • prepared/generic plan 与参数裁剪不确定性;
  • cross-partition query/index/maintenance 复杂度;
  • migration、default partition 和 late-arriving data 处理。

key 选择

策略适合风险
RANGE(time/id)时间生命周期、递增范围hot partition、时区/边界、未来 partition
LIST(tenant/region/state)少量稳定离散域key 增长、skew、default 膨胀
HASH(key)均匀分布/并行维护生命周期语义弱、重分片成本
multi-level同时有生命周期与隔离partition 数和运维复杂度乘积

使用 [start, end) 边界,显式时区与 catch-all/拒绝策略。parent-level PRIMARY KEY / UNIQUE 必须满足当前 PostgreSQL 对 partition key 的要求;不能假设多个本地索引自动 提供任意全局唯一性。

决策交付物

decision: partition | do-not-partition | revisit
key_and_method:
business_and_retention_boundary:
query_predicates:
partition_count_now_and_horizon:
unique_fk_constraints:
late_and_future_data:
automation_owner:
evidence:
revisit_trigger:

D.2 ch07:规划时/执行时裁剪与父表统计

ch07.4EXPLAIN 区分:

plan-time pruning
  常量/可折叠表达式在规划时排除 partition

execution-time pruning
  parameter/nested-loop value 在 executor 初始化或运行阶段排除

检查:

SHOW enable_partition_pruning;

EXPLAIN (ANALYZE, BUFFERS, SETTINGS, VERBOSE)
SELECT ...
FROM partitioned_parent
WHERE partition_key >= $1
  AND partition_key <  $2;

关注:

Subplans Removed
loops = 0
实际访问的 child relation
parent/child row estimates
planning time and partition count

常见裁剪失败

  • predicate 没落在 partition key;
  • 隐式 cast、时区或函数阻止匹配;
  • wrapper/表达式与 partition bound 不同;
  • generic/custom prepared plan 行为不同;
  • join value 只能在执行阶段知道;
  • default partition 覆盖过大;
  • 误把 constraint exclusion 与 declarative pruning 混为一谈。

“查询结果快”不证明裁剪;小数据可能全扫仍快。保存 plan、参数、table definition、 statistics 和 server version。

statistics

parent/child 的 statistics、autovacuum/analyze 与增量数据分布可能不同。检查:

parent estimates vs actual
hot/current child statistics freshness
partition key and correlated columns
default partition skew
newly attached partition analyze state

不要只在一个 child ANALYZE 后推断 parent workload 已正确估算。

D.3 ch11:在线分区化

ch11.4 把“改成分区表”当迁移项目:

expand
  create partitioned parent, children, indexes, constraints

migrate
  backfill bounded ranges; capture concurrent delta

validate
  counts/digests/constraints/query plans/replica lag

cut over
  bounded lock; route old/new application versions

contract
  stop dual path; retain rollback; retire old table

PostgreSQL 不能把普通表原地无成本变成 partitioned parent。迁移策略可用新表、shadow write、logical change capture、短暂停写或 ATTACH PARTITION,但每种都要重新验证 锁、WAL、trigger/FK、sequence、replica 和 rollback。

ATTACH PARTITION

若待 attach 表已有能证明 bound 的匹配 CHECK constraint,PostgreSQL 可避免为验证 partition constraint 扫描它;具体锁与扫描行为绑定版本与对象状态。default partition 还可能需要验证它不含新 range 数据。执行前:

exact bound and no overlap
matching columns/types/collations
constraints and indexes
no rows outside bound
default partition impact
parent/child concurrent traffic
lock timeout and stop

attach 后再验证 parent query、direct child access、privilege、trigger、FK、stats 与 backup/replication。

dual write 风险

应用双写或 trigger capture 可能产生:

ordering difference
partial commit across systems
duplicate/retry
hidden trigger side effect
sequence drift
old/new schema incompatibility

优先同一 transaction 内可验证机制;仍需 source-of-truth、reconciliation 和 cutover watermark。不要以两个 row count 相等作为唯一证明。

D.4 ch16:时间分区场景

ch16.2 先定义时间:

event time       业务事件发生
ingest time      系统接收
effective time   业务事实生效
system time      数据库记录版本

partition key 必须匹配主要生命周期和查询。按 ingest time 分区容易接收 late event, 却不一定裁剪 event-time 查询;按 event time 分区需要 future/late/default 策略。

边界规则

store timestamptz for global instant
choose one canonical timezone for bounds
use half-open [from, to)
generate future partitions ahead of time
alert before current partition end
define late-arrival and backfill authority

不要用本地日期字符串猜 DST 边界。保存实际 bound:

SELECT
    inhparent::pg_catalog.regclass AS parent,
    inhrelid::pg_catalog.regclass AS child,
    pg_catalog.pg_get_expr(c.relpartbound, c.oid) AS bound
FROM pg_catalog.pg_inherits AS i
JOIN pg_catalog.pg_class AS c ON c.oid = i.inhrelid
WHERE inhparent = 'schema.parent'::pg_catalog.regclass
ORDER BY child::text;

partition 内索引

时间 range 裁剪减少 child 数,child 内仍要按谓词、排序和 join 选 B-tree/BRIN/GiST 等。 BRIN 依赖物理相关性,不是“时序表默认更快”;空间 + 时间查询还要验证两种 selectivity 如何组合。

D.5 ch28:分区生命周期、冻结与退役

ch28.7 把 partition state 作为有限状态机:

future -> writable -> sealed -> validated -> archived
       -> detached -> retained -> dropped

每次 transition 有:

partition:
bound:
state_before:
preconditions:
business_retention:
legal_hold:
backup_or_export:
freeze_and_visibility:
dependent_objects:
action:
validation:
rollback_or_re-attach:
owner:

sealed 不等于无需 vacuum

旧 partition 即使不再业务写入,仍可能需要:

  • freeze XID/multixact;
  • 清理过去更新留下的 dead tuple;
  • 更新 visibility map;
  • 完成 index/constraint validation;
  • 处理仍引用它的 snapshot/slot/prepared transaction。

观察每个 child 的 age、stats 和 size,不只看 parent aggregate。

detach/drop 与大 DELETE

按完整 partition 退役通常能避免逐行 DELETE 的大量 WAL/dead tuples,但 DDL 仍有锁、 依赖、replication、backup 与业务风险。先确认:

bound fully outside retention
no legal/audit hold
archive/export is readable
queries no longer require it
FK/view/publication/privilege dependencies understood
exact partition identity
rollback window

DETACH 后对象仍占空间;DROP 才释放 relation,且是不可逆 schema/data action。不要 把 retention policy 直接变成无人审批的自动 drop。

五章闭环检查

ch04 decision still valid?
ch07 representative queries prune?
ch11 migration/cutover evidence retained?
ch16 time semantics and late data correct?
ch28 creation/seal/archive/drop automation healthy?

任一答案未知,先修生命周期合同,不急于增加 partition 数。


返回附录目录 · 对象与证据速查 · ch04 分区决策门 · 查看全书目录

最后更新于