☰
PostgreSQL与Hologres表结构查询:系统表、视图与实用速查
2026/10/19 5:56:52 网站建设 项目流程

PostgreSQL与Hologres表结构查询语句完全指南

前两天在帮同事排查一个数据同步问题,源头表在PostgreSQL,目标表在Hologres,两边字段对不上,排查了半天才发现是其中一方的表结构已经变了,但同步任务还在按旧结构跑。这类问题的根子往往只有一个:我们根本没快速拿到准确的表结构定义,光靠眼睛对比建表语句太容易漏。

不管是日常开发、数仓建模,还是排查数据问题,查表结构都是最高频的操作之一。PostgreSQL作为经典的关系型数据库,表结构查询有自己的一套体系;Hologres虽然是兼容PostgreSQL协议的数仓产品,但在表结构查询上既有相似之处,又有不少差异。这篇文章就把两边的表结构查询语句系统梳理一遍,包括系统表、系统视图、元数据函数的配合使用,以及我实际踩过的坑。

1. 两种数据库查表结构的场景差异

先说清楚为什么要把这两者放在一起聊。很多团队的业务数据落在PostgreSQL,分析场景又用Hologres做数仓,两边表结构需要经常对齐。如果你只用过其中一种,往往会默认另一种的查询方式也差不多,实际用下来会发现细节差异不小。

PostgreSQL查表结构,核心是它的系统目录(System Catalog)和information_schema。系统目录就是pg_catalog下的那一堆表,比如pg_class存表、视图、索引等关系的基本信息,pg_attribute存表的列定义,pg_namespace存命名空间也就是schema。information_schema是SQL标准定义的视图层,PostgreSQL实现得比较完整,查columns、tables这些视图就行。

Hologres这边要特别留意,它虽然兼容PostgreSQL协议,但底层是分布式存储引擎,表结构里多了不少分布式概念。比如distribution_key决定数据怎么分布,table_group是物理存储分组的逻辑概念,shard数影响并发能力,还有单独的Binlog、时间分区等配置。这些在PostgreSQL里都没有对应概念,所以只靠PostgreSQL那套系统表是拿不全的。

举个实际例子,你在PostgreSQL里查一张表的列信息,用information_schema.columns就够了,但在Hologres里想确认一张表是不是分区表、分区键是哪几个字段、分布键设置是否合理,information_schema.columns压根不给这些信息,得去查Hologres自己的系统表。

所以这篇文章的核心逻辑是:先把PostgreSQL的通用查询方式讲透,再讲Hologres的异同和扩展查询,最后汇总成一套可以实际落地的速查方案。两边的语句我都在测试环境跑过,给出的都是验证过可用的写法。

2. PostgreSQL表结构查询:系统表与视图的配合使用

PostgreSQL查表结构的方式很多,不同场景适合不同写法。初学的时候我习惯直接看pgAdmin的图形界面,但写了几年SQL之后发现,命令行和SQL语句才是最快最可靠的,尤其在批量处理、自动化脚本、排查问题的时候。

2.1 通过information_schema查询基础表结构

information_schema是SQL标准视图,好处是结构清晰、字段名规范,适合不太熟悉pg系统表的同学。查一张表的所有列,最常用的写法是:

select column_name, data_type, character_maximum_length, is_nullable, column_default from information_schema.columns where table_schema = 'public' and table_name = 'user_info' order by ordinal_position;

这个查询返回字段名、数据类型、长度、是否可空、默认值,日常开发看的维度基本够了。有些字段需要注意,比如character_maximum_length只有varchar这类有长度限制的类型才有值,int、bigint、timestamp这些是没有的。另外numeric类型精度要看numeric_precision和numeric_scale两个字段。

我还习惯加一个聚合版本,一张表一行记录,把所有列拼起来,方便快速浏览:

select string_agg(column_name || ' ' || data_type, ', ' order by ordinal_position) as columns from information_schema.columns where table_schema = 'public' and table_name = 'user_info';

这样出来的结果类似id bigint, name varchar, create_time timestamp,对快速确认字段构成特别有用。

2.2 使用pg_catalog系统表获取更深层信息

information_schema虽然直观,但有些信息它给不了,最典型的就是注释(comment)和表所属的owner。这些藏在pg_catalog里。

查表基本信息用pg_class,关联pg_namespace拿schema名,关联pg_roles拿owner:

select n.nspname as schema_name, c.relname as table_name, c.relkind, pg_get_userbyid(c.relowner) as table_owner, obj_description(c.oid) as table_comment from pg_class c left join pg_namespace n on n.oid = c.relnamespace where n.nspname = 'public' and c.relname = 'user_info';

relkind字段很有用,r代表普通表,v代表视图,m代表物化视图,p代表分区表。这个字段在排查"我建的表怎么不见了"这类问题时特别关键,因为你可能压根建的是个视图或者分区父表。

查列的详细信息要关联pg_attribute,同时排除掉系统默认的隐藏列:

select a.attname as column_name, format_type(a.atttypid, a.atttypmod) as column_type, a.attnotnull as not_null, col_description(a.attrelid, a.attnum) as column_comment, d.adsrc as default_value from pg_attribute a left join pg_attrdef d on d.adrelid = a.attrelid and d.adnum = a.attnum where a.attrelid = 'public.user_info'::regclass and a.attnum > 0 and not a.attisdropped order by a.attnum;

这里用了'public.user_info'::regclass这种类型转换写法,PostgreSQL会自动把表名转成内部oid,比先查oid再关联方便很多。format_type函数能把内部类型格式化成可读的类型字符串,比如character varying(64),比information_schema拆成data_type和character_maximum_length两个字段更直观。

2.3 利用psql元命令快速查看完整表定义

如果只是自己在命令行确认表结构,写SQL反而绕了。psql提供了现成的元命令,最常用的是\d系:

\d public.user_info

这个命令输出很全,列、索引、约束、触发器全都列出来。后面加+变成\d+ public.user_info,还会多出存储参数、表空间、统计信息这些。如果你想把表结构直接导出成SQL语句,PostgreSQL内置了pg_dump:

pg_dump --table=public.user_info --schema-only --no-owner

这条命令的输出就是标准的建表语句,包括约束、索引、注释,拿来重建表或者做结构对比非常方便。我在做多环境表结构一致性检查的时候,就靠它把两边的表定义导出来做diff。

小技巧:\d系列命令在排查问题时往往比SQL快得多,但自动化脚本里还是得用SQL或pg_dump,因为元命令是交互式客户端的功能,不能直接在程序里调用。

3. Hologres表结构查询:兼容与扩展并存

Hologres和PostgreSQL的关系,用一句话概括就是"协议兼容、内核不同"。你在Hologres里能跑PostgreSQL那套information_schema和大部分pg_catalog查询,但拿到的是Hologres自己实现的元数据。这就带来了两个问题:一是部分PostgreSQL系统表在Hologres里没有或字段不全,二是Hologres独有的分布式表属性用PostgreSQL那套查不到。

3.1 基础列信息查询的兼容性

先看最基础的,查一张Hologres表的列信息:

select column_name, data_type, is_nullable, column_default from information_schema.columns where table_schema = 'public' and table_name = 'ods_user_info' order by ordinal_position;

这个在Hologres里能跑通,结果和PostgreSQL几乎一样。但注意,character_maximum_length在Hologres里经常是空的,varchar类型不会像PostgreSQL那样返回长度,因为它内部存储方式不同。如果发现Hologres和PostgreSQL查出来的类型长度对不上,先别急着怀疑数据出错,这是两边的元数据口径差异。

Hologres也实现了部分pg_catalog兼容,比如你可以用pg_class查表是否存在:

select n.nspname as schema_name, c.relname as table_name, c.relkind from pg_class c left join pg_namespace n on n.oid = c.relnamespace where c.relname = 'ods_user_info';

但在Hologres里,有些PostgreSQL的系统表是空表或者压根不存在的,比如pg_attrdef在Hologres里基本查不到默认值。所以默认值这块,我在Hologres里基本不依赖PostgreSQL那套,而是用Hologres自己的函数。

3.2 用holo侧系统表查分布式表属性

Hologres表结构真正独特的地方在于分布式属性,这些才是建表时最需要关心的。查分布键用holo_shard_info这个系统表:

select table_name, shard_count, distribution_key from holo_shard_info where table_name = 'ods_user_info';

distribution_key列会返回分布键的字段名,比如id或者id,name。shard_count是分片数,这个参数在Hologres里直接影响查询和写入性能。

查表的分区信息要用另一个系统表:

select partition_key, partition_interval from holo_partition_info where table_name = 'ods_log_data';

分区键和时间间隔都在这,partition_interval常见的值有day、month,对应日分区和月分区。

还有table_group这个物理存储分组的概念,PostgreSQL里完全没对应:

select table_name, table_group_name from holo_table_info where table_name = 'ods_user_info';

table_group在Hologres里关联了存储资源和查询性能,多张表放同一个table_group可以共享存储。如果你在排查"为什么有些表查询快有些慢"的问题,table_group和shard_count是两个最先要看的地方。

3.3 使用holo_get_table_ddl快速拿到建表语句

Hologres提供了几个便捷函数,最实用的是holo_get_table_ddl。它把一张表的完整建表语句直接生成出来,包括分布键、分区配置、表属性这些手写容易漏的东西:

select holo_get_table_ddl('ods_user_info');

输出类似这样:

CREATE TABLE public.ods_user_info ( id bigint NOT NULL, name text, create_time timestamp with time zone, PRIMARY KEY (id) ) WITH ( distribution_key = 'id', table_group = 'default' );

这个函数有两个参数的重载形式,第二个参数控制是否折叠成一行:

select holo_get_table_ddl('ods_user_info', true);

写脚本批量比对表结构的时候,我用这个函数把所有表的建表语句导出来做文本diff,比手动逐列对比靠谱得多。

注意:holo_get_table_ddl返回的建表语句里,字段顺序和原始建表可能不完全一致,Hologres会按自己的存储顺序排列。做对比时不要纠结顺序,重点看字段名和属性配置。

4. 常见问题与排查技巧实录

两边的差异和坑,我在实际项目中都遇到过。下面列几个典型场景和对应的排查方式。

4.1 "查不到某张表的表结构"

这个问题的排查思路要看表是否存在、是否在当前schema下、当前用户是否有权限。我习惯先用一条SQL定位:

select table_schema, table_name, table_type from information_schema.tables where table_name like '%user_info%';

PostgreSQL和Hologres都能跑这条。如果结果为空,说明表确实不存在或者不在当前连接的数据库中。注意PostgreSQL的搜索路径(search_path),如果表建在别的schema下而search_path没包含它,直接查\d 表名会提示找不到。

Hologres还要多查一步:确认是不是在某个内部schema下。Hologres里除了public,还有s4、s7等内部schema,普通用户默认看不到这些schema下的表。

4.2 两边查出来的字段类型不一致

PostgreSQL的character varying(255)到了Hologres变成了text,这种情况经常发生。Hologres的存储引擎对字符串类型做了简化,varchar和text最终都可能显示成text。这不是数据问题,是类型系统差异。

做字段映射时,我建议按逻辑类型判断,不要按物理类型硬比。比如对比"是否是字符串类型",把varchar和text归成一类,再去比长度限制。长度限制在Hologres里通常不生效,所以如果你的应用强依赖varchar长度限制,从PostgreSQL同步到Hologres后要额外关注业务侧的校验逻辑。

4.3 查看表注释和列注释

PostgreSQL里查所有列注释,我常用这个:

select obj_description('public.user_info'::regclass), col_description('public.user_info'::regclass, 1);

obj_description查表注释,col_description查指定列注释,第二个参数是列的序号(从1开始)。批量查所有列的注释可以配合pg_attribute:

select a.attname, col_description(a.attrelid, a.attnum) as column_comment from pg_attribute a where a.attrelid = 'public.user_info'::regclass and a.attnum > 0 and not a.attisdropped;

Hologres里注释查询方式和PostgreSQL兼容,但有个细节要留意:如果你用HoloStudio的界面建表,注释可能存的位置和直接执行comment语句不完全一样,偶尔会出现查不到的情况。真遇到这种问题,优先看holo_get_table_ddl的输出,它会把注释一并体现在DDL里。

4.4 快速确认表结构是否发生变化

做数据同步的时候,经常要确认源表和目标表结构是否一致。我的做法是两边各跑一条语句生成结构指纹,然后比对:

PostgreSQL:

select string_agg(column_name || ':' || data_type, ',' order by ordinal_position) as schema_fingerprint from information_schema.columns where table_schema = 'public' and table_name = 'user_info';

Hologres:

select string_agg(column_name || ':' || data_type, ',' order by ordinal_position) as schema_fingerprint from information_schema.columns where table_schema = 'public' and table_name = 'ods_user_info';

把两边结果放在一起有没有不一样。更完整的做法是连注释、默认值、约束一起拼进去,但大多数场景下字段名和类型的比对已经能发现绝大部分问题。

4.5 查询所有表的表结构清单

有时候要梳理整个库的表和字段情况,单表查询效率太低。我常用这个汇总查询:

select table_name, column_name, data_type, ordinal_position from information_schema.columns where table_schema = 'public' order by table_name, ordinal_position;

在这个结果上再套一层聚合,就能得到每张表的字段清单。类似的写法在PostgreSQL和Hologres里都可以跑,只是数据类型的准确性有差异,上面已经说过。

Hologres如果想连同分布键、分片数一起列出,可以关联holo_shard_info:

select t.table_name, s.shard_count, s.distribution_key from holo_shard_info s left join information_schema.tables t on t.table_name = s.table_name where t.table_schema = 'public' order by t.table_name;

这个清单对库表巡检特别有用,一眼能看出哪些表没设分布键或者分布键设计可能不合理。

5. 通用速查:一条SQL覆盖常用结构维度

最后整理一个我在两边都经常用的组合查询,把列名、类型、默认值、可空、注释一次性查出来。

PostgreSQL完整版:

select a.attname as column_name, format_type(a.atttypid, a.atttypmod) as column_type, a.attnotnull as not_null, coalesce(pg_get_expr(d.adbin, d.adrelid), '') as default_value, col_description(a.attrelid, a.attnum) as comment from pg_attribute a left join pg_attrdef d on d.adrelid = a.attrelid and d.adnum = a.attnum where a.attrelid = 'public.user_info'::regclass and a.attnum > 0 and not a.attisdropped order by a.attnum;

这里用了pg_get_expr来解析默认值的表达式,比直接查adsrc更通用,能正确处理带函数调用的默认值,比如now()、nextval('seq')这些。

Hologres兼容版:

select column_name, data_type, is_nullable, column_default from information_schema.columns where table_schema = 'public' and table_name = 'ods_user_info' order by ordinal_position;

再配合:

select holo_get_table_ddl('ods_user_info');

在实际使用中,我一般先用holo_get_table_ddl拿到完整建表语句确认整体结构,再用information_schema或pg_attribute查列级明细,两者配合基本覆盖所有场景。PostgreSQL那边则优先用pg_attribute系查询,因为能拿到注释、默认值和完整类型格式,信息更全。

最后再分享一个小经验:写自动化脚本做表结构检查时,不要把列信息查询和属性信息查询混在一段逻辑里。分开跑、分开处理,拼接的时候再合并,排查问题时会清晰很多。PostgreSQL的pg_attribute和Hologres的holo_get_table_ddl是各自的"信息最全"入口,从这两个入手效率最高。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询