4、关系型数据库元数据采集(下):PostgreSQL 与 Oracle 元数据采集要点
上一章我们聊了 MySQL 的采集套路。这一章,咱们把目光转向 PostgreSQL 和 Oracle。
说实话,这两个数据库在元数据采集上,比 MySQL 要「讲究」一些。PG 的 information_schema 很标准,但有些关键信息藏在系统表里。Oracle 呢,嗯,它的数据字典庞大得像个迷宫,我第一次接触时也绕了不少弯路。
今天我就把这两套系统的采集要点拆开揉碎了讲给你听。你想想看,搞懂了它们的脾性,以后不管换什么数据库,心里都有底。
4.1 PostgreSQL:标准与扩展并存
PostgreSQL 的元数据体系,说白了就是两条腿走路:一条是 SQL 标准定义的 information_schema,另一条是 PG 自己的系统表(pg_catalog)。
我个人习惯,能用 information_schema 的绝不动系统表。但有些场景,比如获取表的物理存储大小、索引的详细定义,你就得去翻 pg_catalog 了。
4.1.1 核心采集对象与 SQL
我们先看最常用的几个采集点。我把它们整理成了一张表,方便你对照着用。
| 采集目标 | 核心视图/表 | 关键字段 |
|---|---|---|
| 数据库列表 | pg_database |
datname, datdba, encoding |
| 模式列表 | information_schema.schemata |
schema_name, schema_owner |
| 表与视图 | information_schema.tables |
table_name, table_type, table_schema |
| 字段信息 | information_schema.columns |
column_name, data_type, is_nullable |
| 主键约束 | information_schema.table_constraints + key_column_usage |
constraint_name, column_name |
| 索引信息 | pg_indexes |
indexname, indexdef, tablespace |
| 表大小 | pg_table_size(), pg_total_relation_size() |
函数返回值(bytes) |
举个例子,采集某个模式下所有表的字段信息,我会这么写:
SELECT
c.table_schema,
c.table_name,
c.column_name,
c.data_type,
c.character_maximum_length,
c.is_nullable,
c.column_default
FROM information_schema.columns c
WHERE c.table_schema NOT IN ('pg_catalog', 'information_schema')
ORDER BY c.table_schema, c.table_name, c.ordinal_position;
information_schema 查询速度通常不错。但如果你的数据库里有几千张表,记得给 table_schema 和 table_name 加上索引,否则第一次全量采集可能会有点慢。
4.1.2 避坑:系统表与权限
我曾经在一个生产环境上踩过坑。当时用 pg_catalog.pg_class 去拿表的 OID,结果发现有些表查不到。后来一查,原来是采集账号没有 pg_catalog 模式的使用权限。
所以,这里有个原则:优先用 information_schema。它只返回当前用户有权限看到的对象,不容易出权限问题。如果非要用系统表,记得给账号加上 pg_read_all_stats 或类似角色。
4.2 Oracle:数据字典的庞大家族
Oracle 的元数据采集,嗯,怎么说呢,它更像是在跟一个老派的贵族打交道——规矩多,但功能强大。
Oracle 的数据字典分为三类视图:USER_、ALL_ 和 DBA_。我个人建议,能用 ALL_ 就别用 DBA_,除非你确实需要全局视角。因为 DBA_ 视图通常需要更高的权限,而且查询开销更大。
4.2.1 核心采集对象与 SQL
Oracle 的采集重点,除了表、字段、索引这些常规项,还有几个特有的东西:表空间、分区表和物化视图。下面这张表帮你理清脉络。
| 采集目标 | 核心视图 | 关键字段 |
|---|---|---|
| 用户/模式 | ALL_USERS |
username, created |
| 表与视图 | ALL_TABLES, ALL_VIEWS |
table_name, owner, tablespace_name |
| 字段信息 | ALL_TAB_COLUMNS |
column_name, data_type, data_length |
| 约束信息 | ALL_CONSTRAINTS + ALL_CONS_COLUMNS |
constraint_type, column_name |
| 索引信息 | ALL_INDEXES + ALL_IND_COLUMNS |
index_name, uniqueness, column_position |
| 表空间 | DBA_TABLESPACES |
tablespace_name, block_size, status |
| 分区信息 | ALL_TAB_PARTITIONS |
partition_name, high_value, num_rows |
比如,采集某个用户下所有表的字段信息,我会这样写:
SELECT
tc.owner,
tc.table_name,
tc.column_name,
tc.data_type,
tc.data_length,
tc.data_precision,
tc.data_scale,
tc.nullable
FROM ALL_TAB_COLUMNS tc
WHERE tc.owner = 'YOUR_SCHEMA'
ORDER BY tc.table_name, tc.column_id;
ALL_TAB_COLUMNS 中,data_length 是字节长度,data_precision 和 data_scale 才是数字类型的精度和小数位。别搞混了,否则采集到的元数据会误导下游的数据建模。
4.2.2 避坑:分区表与 LOB 字段
Oracle 的分区表是个好东西,但采集元数据时容易出问题。你想想看,一张分区表可能有几百个分区,如果每个分区都当成独立表去采集,那元数据量会爆炸。
我曾经接手过一个项目,之前的采集脚本把每个分区都当成一张表,结果元数据仓库里多了几万条「假表」记录。后来我改成了只采集分区表的父表信息,分区细节通过 ALL_TAB_PARTITIONS 单独存储,这才把问题解决。
另外,LOB 字段(如 CLOB、BLOB)在 ALL_TAB_COLUMNS 里也能查到,但它们的 data_length 通常是 4000 或一个固定值,并不代表实际存储大小。如果你需要统计 LOB 段的存储量,得去查 DBA_LOBS 或 ALL_LOBS。
4.3 两种数据库的采集策略对比
为了方便你选型,我把 PG 和 Oracle 的采集策略做了个对比。说白了,就是帮你判断:什么时候该用哪种方式。
| 对比维度 | PostgreSQL | Oracle |
|---|---|---|
| 标准兼容性 | 高(information_schema 完整) |
低(以自有视图为主) |
| 权限模型 | 基于模式(schema) | 基于用户(schema = user) |
| 性能瓶颈 | 系统表扫描(pg_catalog) |
DBA_ 视图全量查询 |
| 特有采集项 | 表大小函数、自定义类型 | 表空间、分区、物化视图 |
| 推荐采集方式 | information_schema + 少量 pg_catalog |
ALL_ 视图 + 按需使用 DBA_ |
4.4 本章知识体系图
下面这张图,帮你把 PG 和 Oracle 的采集要点串起来。你可以把它当成一个快速索引,以后做采集时直接对照着看。
4.5 本章小结
PostgreSQL 和 Oracle 的元数据采集,本质上都是在跟数据字典打交道。PG 胜在标准、清爽,Oracle 胜在全面、强大。
我个人觉得,搞懂这两个数据库的采集,你基本就能应对市面上 80% 的关系型数据库了。因为它们的思路是相通的:先找标准视图,再补系统表,最后处理特殊对象。