内容提要
PostgreSQL 的 GRAPH_TABLE 在解析层将图查询重写为对底层表的普通连接,由常规优化器生成计划,因此性能可预测,所需索引与等价 SQL 连接相同,EXPLAIN 直接显示连接树。边表主键索引源列,反向遍历需在目标列加索引,可提速约 20 倍。PG 19 尚不支持变长模式与最短路径,可用 WITH RECURSIVE 变通。
延伸解读
索引策略:正向与反向遍历的关键差异
边表主键 (a, b) 天然索引源列 a,因此正向遍历(如“某人认识谁”)可高效利用索引。但反向遍历(如“谁认识某人”)需按目标列 b 查找,主键无法覆盖,导致顺序扫描。文章示例中,为 b 列添加索引后,查询时间从 3.1 毫秒降至 0.16 毫秒,缓冲区命中从 287 降至 29,提速约 20 倍。这提醒我们:若图查询涉及反向边,务必在目标列上建索引,否则性能会显著下降。
执行计划与优化器行为:与普通连接无异
GRAPH_TABLE 在解析层被重写为对底层表的普通连接,因此 EXPLAIN 直接显示连接树,没有图专用计划节点。计划形状由模式形状机械决定:两跳模式生成五路连接,三跳生成七路连接。优化器使用与常规 SQL 相同的成本模型和统计信息选择连接顺序与方法。这意味着性能可预测,诊断方法不变——发现意外顺序扫描时,添加缺失索引即可。
PG 19 的功能边界与变通方案
PostgreSQL 19 的 SQL/PGQ 实现尚不支持变长模式、最短路径和多模式 MATCH。对于变长路径,可用 WITH RECURSIVE 模拟,例如查询“从顶点 2 出发 1 到 3 跳内可达的所有人”。多模式查询可通过两个 GRAPH_TABLE 调用并基于投影的顶点 ID 连接来实现。这些变通方案虽不如未来语法优雅,但能组合使用,满足当前需求。
适用场景与迁移建议
GRAPH_TABLE 适合固定形状的多跳模式,如朋友的朋友、同事查找或“我朋友的雇主”等遍历。纯聚合查询无需遍历,两种形式均可。迁移时,可在现有模式上添加 CREATE PROPERTY GRAPH 覆盖层(仅元数据操作),将一条多连接查询改写为 GRAPH_TABLE 查询,并对比 EXPLAIN 输出。计划应几乎相同,差异通常来自图形式为类型检查引入的额外顶点表连接。
Q&A
PostgreSQL 19 的 GRAPH_TABLE 是如何执行图查询的?
GRAPH_TABLE 在解析层将图查询重写为对底层表的普通连接,然后由常规优化器生成执行计划。因此性能可预测,EXPLAIN 直接显示连接树,没有图专用的计划节点。
使用 GRAPH_TABLE 需要添加哪些索引?
所需索引与等价 SQL 连接相同。边表的主键索引源列,支持正向遍历;如果需要进行反向遍历(例如查询“谁认识某人”),则需要在目标列上添加索引。
反向遍历图时没有索引会有什么性能问题?
反向遍历会按目标列查找,如果目标列没有索引,PostgreSQL 会执行顺序扫描,读取整个边表。添加目标列索引后,查询时间可从 3.1 毫秒降至 0.16 毫秒,缓冲区命中从 287 降至 29,速度提升约 20 倍。
PostgreSQL 19 的 GRAPH_TABLE 有哪些功能限制?
PostgreSQL 19 的 GRAPH_TABLE 尚不支持变长模式、最短路径、量化模式和多模式 MATCH 等特性。其中变长模式和最短路径影响较大,但可以使用 WITH RECURSIVE 作为变通方案。
如何用 WITH RECURSIVE 实现变长路径查询?
对于“从顶点 2 出发 1 到 3 跳内可达的所有顶点”这类查询,可以使用 WITH RECURSIVE 递归地遍历边表,逐跳扩展路径,直到达到最大跳数。这是变长模式的标准变通方法。
GRAPH_TABLE 适合哪些使用场景?
GRAPH_TABLE 适合固定形状的多跳模式查询,尤其是涉及多种顶点和边类型的场景,例如朋友的朋友、同事查找或“我朋友的朋友”等遍历。对于不需要遍历的纯聚合查询,使用 GRAPH_TABLE 或普通 SQL 均可,选择可读性更好的形式。