编程 图查询塞进关系库:Apache AGE 自建压测的读数与建议

2026-09-08 02:10:02

Apache AGE 压测实录:PostgreSQL 里的图数据库扛不扛得住

故事从几个 Apache AGE 的 segfault 开始。年轻扩展出段错误不算稀奇,但它带出一个问题:稳定性尚摇摇欲坠时,性能如何? 而真正的障碍是——没有现成的 AGE 基准:没有现成 benchmark、没有已发布的结果。于是作者基于 LDBC SNB 数据模型自己造了压测。

为什么要把图塞进 PostgreSQL

关系模型答"Alice 住纽约"要 JOIN 四张表;图模型就是一个 Alice 顶点、一个 New York 顶点、一条 lives-in 边。Apache AGE(A Graph Extension)让你直接在 PostgreSQL 里用 openCypher(Neo4j Cypher 的开源版本)查图,不用部署独立图数据库、不用跨系统同步、团队不用学新栈。代价在后面:openCypher 是开放版本而非 Cypher 完整拷贝。

深度 2 层的"朋友的朋友",SQL 开始长递归 CTE 和多个 JOIN;Cypher 只是把 [:KNOWS] 改成 [:KNOWS*1..2]——三个字符。三层深度后,可读性差距像"诗 vs 洗衣机说明书"。

内部机制

连接是标准扩展流程(CREATE EXTENSION age + LOAD + search_path 指向 ag_catalog)。create_graph 自动建同名 schema 和两张父表 ag_label_vertex/ag_label_edge,Cypher 引入类型时自动建继承子表,无需手动 CREATE TABLE。顶点属性是 agtype(JSONB 的超集),边额外带 start_id/end_id。顶点属性几乎总比边重——边通常一两个字段,顶点可以带十几个属性。

自建基准

数据模型和查询集取自 LDBC SNB,内部工具 pg_microbench 直接对接 AGE,19 个测试场景分三组:短读、重读、写。社交网络 schema(Person/Post/Comment/Forum/Tag…),数据按 SF 缩放:SF=1(约 2 万对象)、SF=10(约 20 万)、SF=100(约 200 万)。索引专门建了两种:id 上的 B-tree(仅当查询用 WHERE n.id = 'value' 时才需要,否则冗余)、properties 上的 GIN。

关键数字

负载TPS状态
短读~40000稳定
路径查找~7补丁进行中
边插入30000稳定
顶点插入(patch 前)1000 → 退化已向社区提交补丁
顶点插入(patch 后)15000稳定

作者发现真正的瓶颈有时不是图遍历算法或查询语言复杂度,而是一次插入时顶点存在性检查里的单次 SeqScan——本不该出现在那里。

实践建议

  • id 建 B-tree 索引、properties 建 GIN 索引——必做
  • 查询永远指定 label,否则全表 SeqScan;
  • 从选择性更强的一端起步,尽早过滤;
  • 路径查找锁死深度、偏好单向查询;
  • 重型遍历把 work_mem 提到 120MB+;
  • 小心 OPTIONAL MATCH。

结论:PostgreSQL 之上的图模型可行,短查询和中复杂负载下 AGE 完全可用;但与 Neo4j 相比,大图和路径查找仍是 Neo4j 更快——AGE 开发者自己的回答是"Neo4j 是为图从零建的,AGE 叠在关系库之上,差距靠补丁收窄"。

来源:Apache AGE under load: how PostgreSQL graphs behave under stress - DEV Community

复制全文 生成海报 PostgreSQL 图数据库 性能 压测

推荐文章

程序员茄子在线接单