3. 迁移升级前的环境与资产盘点
数据库迁移或版本升级失败,很少是因为“命令敲错了”,更多是因为盘点不完整:某个业务库依赖了 postgres_fdw 外部表、某个定时任务在凌晨两点调用了一个即将被废弃的函数、连接池里还残留着指向旧主库的地址、逻辑复制槽因为长期未消费而堆积了数十 GB WAL。这些问题在切换前不暴露,切换后集中爆发。因此,盘点的目标不是“列个清单”,而是形成两份可执行产物:资产清单(有哪些对象、多少、多大、谁在用)和依赖图谱(谁依赖谁、断开会怎样)。
一、盘点范围:从实例到外部依赖的六个层次
建议按“实例 → 数据库 → 模式 → 对象 → 扩展 → 外部依赖”自顶向下逐层收敛,避免遗漏。每一层都要记录对象数量、体积、访问频率和责任人。
- 实例层:版本号(
SHOW server_version)、架构(x86/ARM)、字符集与排序规则(SHOW server_encoding; SHOW lc_collate;)、时区、最大连接数、共享内存与 WAL 相关参数。排序规则在跨大版本升级时尤其关键,glibc 版本变化可能导致索引顺序不一致。 - 数据库层:库名、大小、Owner、是否允许连接、默认表空间、是否有 template 定制。
- 模式层:schema 列表、权限归属、是否有同名 schema 分属不同角色。
- 对象层:表、分区表、索引、视图、物化视图、序列、函数、触发器、自定义类型、域、规则、事件触发器。
- 扩展层:已安装扩展及其版本,是否为目标版本所支持。
- 外部依赖层:FDW、dblink、逻辑复制、物理复制、外部程序调用、连接池、定时任务、监控与备份工具。
二、用系统目录快速产出对象清单
手工点开客户端逐个数对象不可靠,直接用系统目录查询。下面这组语句可作为盘点脚本的基础,输出结果建议导出为 CSV 存档,作为升级前后的对比基线。
-- 各库大小与连接情况
SELECT datname, pg_size_pretty(pg_database_size(datname)) AS size,
datallowconn, datistemplate
FROM pg_database ORDER BY pg_database_size(datname) DESC;
-- 按 schema 统计对象数量
SELECT schemaname,
count(*) FILTER (WHERE relkind='r') AS 普通表,
count(*) FILTER (WHERE relkind='p') AS 分区表,
count(*) FILTER (WHERE relkind='i') AS 索引,
count(*) FILTER (WHERE relkind='v') AS 视图,
count(*) FILTER (WHERE relkind='m') AS 物化视图
FROM pg_stat_user_tables t
JOIN pg_class c ON c.oid = t.relid
JOIN pg_namespace n ON n.oid = c.relnamespace
GROUP BY schemaname ORDER BY 2 DESC;
-- 已安装扩展及版本
SELECT extname, extversion, nspname
FROM pg_extension e JOIN pg_namespace n ON n.oid = e.extnamespace;
-- 大对象与序列使用情况
SELECT count(*) AS 大对象数 FROM pg_largeobject_metadata;
SELECT schemaname, sequencename, last_value
FROM pg_sequences WHERE last_value IS NOT NULL ORDER BY last_value DESC LIMIT 20;
查询结果中要特别关注三类“隐性资产”:一是无主对象(Owner 是已离职账号),迁移后可能无人有权修改;二是超大单表(超过 100 GB 的表在逻辑迁移中会显著拉长停机窗口);三是序列当前值,逻辑迁移若只搬数据不搬序列,切换后插入会立刻主键冲突。
三、扩展与外部依赖:最容易被低估的风险点
扩展的风险在于“版本绑定”。例如 postgis 2.x 升级到 3.x 存在函数签名变更,pg_stat_statements 需要随大版本重新编译,pg_cron、pg_partman 等则依赖后台 worker 与共享库预加载。盘点时要记录:扩展名、当前版本、目标版本是否提供、是否需要 shared_preload_libraries、是否有数据需要 ALTER EXTENSION ... UPDATE。
外部依赖则要画出“谁连我、我连谁”。常见的有:
- FDW / dblink:本库通过外部表访问其他库,迁移后连接串、认证方式可能失效。
- 复制链路:物理流复制(
pg_stat_replication)、逻辑复制(pg_replication_slots、pg_stat_subscription)。逻辑复制槽若在切换前未消费完,会持续保留 WAL。 - 连接池:PgBouncer、Pgpool 的配置中写死了后端地址与端口,切换时需同步更新并重载。
- 定时任务:crontab、pg_cron、外部调度平台(如 Airflow)中调用的存储过程与函数。
- 监控与备份:Prometheus exporter、pgBackRest、WAL-G 的仓库路径与保留策略。
四、权限体系与依赖图谱
权限盘点要落到“角色—对象—权限”三元组。重点检查:角色继承关系(pg_auth_members)、默认权限(ALTER DEFAULT PRIVILEGES)、行级安全策略(RLS)、以及通过 SECURITY DEFINER 提权的函数。后者在迁移中常被忽略,一旦函数 Owner 变更,权限模型就会整体偏移。
依赖图谱的核心是回答“如果我停掉这个对象,谁会受影响”。可以用 pg_depend 查询视图、物化视图、函数之间的依赖,再叠加应用侧调用关系。下面这张图给出了一次典型盘点的依赖关系示意:
五、形成可执行的资产清单
盘点结果最终要落到一张可填写的清单上,字段不宜过多,但必须能支撑切换决策。下面给出一个可直接使用的示例结构(数值为示例假设,非实测):
| 类别 | 对象/依赖 | 关键信息 | 迁移影响 | 责任人 |
|---|---|---|---|---|
| 实例 | PostgreSQL 12.8 | UTF8 / en_US.UTF-8 | 目标 16 需核对排序规则 | DBA-张 |
| 数据库 | appdb(约 420 GB) | Owner: app_owner | 逻辑迁移停机窗口约 3 小时 | DBA-张 |
| 扩展 | postgis 2.5.5 | 目标需 3.4 | 函数签名变更,需回归测试 | 开发-李 |
| 扩展 | pg_stat_statements 1.7 | 需预加载 | 大版本需重新编译 | DBA-张 |
| 外部依赖 | postgres_fdw → extdb | 外部表 12 张 | 连接串与认证需重建 | 开发-王 |
| 复制 | 逻辑槽 slot_app_sub | 积压 18 GB WAL | 切换前需消费或重建 | DBA-张 |
| 连接池 | PgBouncer 1.18 | 后端指向 10.0.0.11:5432 | 切换时需 reload 配置 | 运维-赵 |
| 定时任务 | pg_cron 每日 02:00 | 调用 sp_daily_rollup() | 函数签名需确认兼容 | 开发-李 |
| 权限 | 角色 app_rw / app_ro | 含 RLS 策略 6 条 | 需整体导出重建 | DBA-张 |
pg_dump --schema-only 生成一份结构快照,与清单交叉核对。凡是“清单里有、快照里没有”或“快照里有、清单里没有”的对象,都是需要人工确认的盲区。
SECURITY DEFINER 函数的 Owner。这五类对象在逻辑迁移中默认不会被完整搬运,必须在切换前单独处理。
完成上述工作后,你会得到两份可交付物:一份是覆盖实例到外部依赖的资产清单,另一份是标注了关键依赖路径的图谱。它们不仅是迁移方案设计的输入,也是切换后回归验证的对照基线——升级完成后,用同样的查询再跑一遍,逐项比对对象数量、扩展版本、序列值与复制状态,就能快速判断迁移是否真正完整。