PostgreSQL 做图数据库这件事,我在不同场合跟人聊过很多次。大多数人的第一反应是:正经图数据库不都该用 Neo4j 吗,为什么要在 PG 里折腾?这个问题问得没毛病,但只适用于“从零开始、且业务一定会以图分析为核心”的场景。实际项目里,大量数据已经躺在 PostgreSQL 里,业务也就偶尔做一次多层关系查询,为了这一个频率不高的需求引入一套独立图数据库,成本并不低——部署、同步、维护、学习成本全都得重新付一遍。
Apache AGE 走的是另一条路:它直接以 PostgreSQL 扩展的形式存在,在原有关系库里加入图模型和 Cypher 查询能力。这意味着你可以继续保留原有表结构,同时针对某个业务域建图、写 Cypher,甚至让 Cypher 和 SQL 在同一个查询里混着用。这篇东西我会把 AGE 的原理、安装、建模、性能优化和常见坑完整过一遍,适合两类人看:一类是 PostgreSQL DBA 想给业务补上图分析能力,另一类是 Python 或后端开发,项目里已经有 PG,不想再额外引一套图库。
1. 为什么要在 PostgreSQL 上做图能力
1.1 关系模型表达“关系”其实并不自然
关系型数据库的核心是表和外键。拿一个典型社交场景举例:user 表存用户,follow 表存关注关系。要查“我关注的人里谁还关注了我”,一条 SQL 靠两三次 JOIN 能写出来,但改成“我关注的人里,谁关注了我没关注的人三层以内的人”,SQL 就难受了——你不知道要 JOIN 几次,只能写递归 CTE,可读性和维护成本直线下降。
图数据库把这种查询变成了自然表达。节点、边、属性三要素一上来,“A 到 B 之间有多远”这类问题就变成了纯粹的路径遍历问题。问题是,一个只有这种低频需求的项目,真要为其引入一套独立存储吗?数据同步、两套查询语言、跨库一致性,每一样都是额外的运维负担。
我当时接手的项目就是这样。用户关系、订单、行为日志全在 PostgreSQL 里,业务提了个需求:识别有组织化特征的批量注册账号——本质就是发现关联密度异常高的用户子图。这个需求不是天天跑,但每周都要用。为它上 Neo4j,属实不划算。
1.2 在扩展与迁移之间做选择
市面上“把图能力做到数据库里”的方案并不多,常见路线有四条:
- 换一套支持图模型的数据库,比如 ArangoDB、NebulaGraph,或者直接用 Neo4j;
- 用 PostgreSQL 的递归 CTE 硬写,查询深度固定时勉强可以,深度不确定时就很痛苦;
- 基于 PostgreSQL 之上的独立图扩展,也就是 Apache AGE 这类;
- 用外部图计算框架,定期把 PG 里的数据导进图引擎做离线计算。
这四种方案我从实现成本、运维负担、实时性和开发效率四个维度比较过。换独立图数据库,意味着引入一个新的存储引擎,数据迁移、双写或多写方案、新语言的培训成本,对于一个以 PG 为数据中枢的团队来说是个不小的冲击。递归 CTE 方案则完全没有建模自由度,写出来的 SQL 极难维护。第三种方案 AGE 的好处在于,它不是一套新数据库,而是一个可以在现有 PG 实例中直接启用的扩展。你的数据依然存在原表里,只是需要同步到图空间时,可以靠查询或 ETL 把关系数据映射成图数据。
我最终选了 AGE 还有一个关键原因:它由 Apache 孵化器毕业,底层扩展机制用的是 PostgreSQL 的 Extension 体系,C 语言实现,扩展能力稳定,而且原厂支持被并入了 PostgreSQL 的插件体系。社区虽然比不了 Neo4j,但文档和版本迭代都比较正常,至少不会停更。
1.3 AGE 解决的四个问题
AGE 对我的实际帮助可以浓缩成四句话:
- 用 Cypher 表达多度关系查询,写起来比嵌套 JOIN 简单一个量级;
- 图和关系表共存于同一数据库,不需要独立部署、不需要额外同步链路;
- 它把图查询的结果封装成普通行返回,能继续 JOIN 回原表,不会形成数据孤岛;
- 对已有系统改动最小,要停用也容易——扩展不用了直接禁用相关 schema 就行,原表完全不受影响。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. Apache AGE 的架构与核心概念
2.1 AGE 到底是什么
一句话说清楚:Apache AGE 是 PostgreSQL 的一个扩展模块,它把你熟悉的 CREATE EXTENSION 机制利用起来,在数据库内部实现了属性图数据模型。属性图模型包括节点、边和属性,AGE 用一个叫 agtype 的数据类型统一承载这些信息。
AGE 的图跟 Neo4j 的图有一个很不一样的地方:AGE 中的图,本质上是一组带有固定表结构的关系表。每创建一个图,AGE 会生成一套内部元数据表,其中最重要的是节点表和边表。你执行 create_graph 时,AGE 自动创建了一个 schema,并在其中维护该图的所有标签表和关系表。理解这一点很关键,因为这意味着你不仅可以使用 Cypher 查询,也可以直接用 SQL 去查看底层存储,甚至在 SQL 中对图数据操作。
2.2 agtype:AGE 的“超级 JSON”
我在 AGE 的官方文档里最初注意到的,不是它支持 Cypher,而是它定义了一种叫做 agtype 的数据类型。它看起来跟 PostgreSQL 原生的 jsonb 很像,但内部结构不同,专门为兼容 Cypher 的属性值设计,可以存储数字、字符串、布尔、数组、对象、顶点、边和路径等。
需要特别提醒的是,如果你在 PostgreSQL 里直接写 `select '{"name": "a"}'::agtyp
