PostgreSQL码农集散地

图数据库到底怎么选

今天想聊一个话题 —— 图数据库到底怎么选。说起来,我过去一年被问得最多的一个问题就是:我们公司要做风控,要查账号、设备、手机号之间的关联路径,这时候到底是该用传统 SQL 的递归 CTE,还是上 GraphBLAS,或者说干脆买一个Neo4j?

这类问题,表面上是技术选型,但本质上是思维方式的选择。你先把"图"理解成什么,决定了后面所有的东西。

好,我先来说说传统的路子。关系数据库跑图问题,用 join、用递归 CTE,这是大多数团队手里已有的武器。它的好处是不用引入新系统,坏处是什么?多跳查询的时候,中间结果容易膨胀,而且写起来相当啰嗦。你要手写递归,然后每一层都要担心展开的深度。

那专用图数据库呢,像 Neo4j 那种,它们用的是 Cypher 或者 openCypher,说的是属性图模型——点、边、标签、属性,这些概念对业务人员很友好,路径查询写起来也直观。但问题是,你又多引入了一个独立系统,数据要同步,运维要加一套。

然后今天要聊的 GraphBLAS,走的是第三条路。它的核心思想是什么?图可以表示成稀疏邻接矩阵,图搜索可以变成矩阵乘法、向量乘法、半环运算。听起来好像很数学,但其实这个思路非常工程化。

举个例子,BFS 广度优先搜索,传统的写法是维护一个 frontier,一个 visited 集合,然后循环遍历邻居。但在 GraphBLAS 的视角里,当前 frontier 就是一个向量,图本身是一个稀疏矩阵,用布尔半环做一次矩阵-向量乘,下一层的候选节点就直接产生了,再用 mask 排除已经访问过的节点。这个过程不需要手写循环——循环被"矩阵乘法"这个操作给抽象掉了。

而且这个写法有一个特别大的好处,叫"算法和实现解耦"。你描述算法的时候只说 mxm、mxv,加一个 semiring,加一个 mask,底层可以选择 CSR、CSC、bitmap 或者 hypersparse 的格式,CPU 可以跑,GPU 也可以跑。SuiteSparse:GraphBLAS 那边甚至在推进 JIT 支持。这意味着你在算法层面的投入,未来是可以跨实现复用的。

但 GraphBLAS 不是银弹,它有自己的适用边界。最不适合的场景是什么?是那种每次 OLTP 写入都必须立刻反映到图查询结果的场景——图数据库处理点边实时更新是很自然的,但 GraphBLAS 的矩阵对象,更适合批量构造然后反复查询。如果你的业务是每次改数据都要立刻查关联路径,那 GraphBLAS 带来的延迟会让你受不了。

还有一个特别容易踩的坑——方向。GraphBLAS 里,A[i,j] 表示的是 i 到 j 的边还是 j 到 i 的边,必须在构造矩阵之前就定义清楚。mxv 和 vxm 代表的传播方向是相反的,如果方向搞反了,BFS 跑出来的结果看起来完全合理,但实际上全是反的。这种 bug 极难发现,因为它跑起来不会报错,只是结果错了。

另外就是"缺失"和"0"的区别。在 GraphBLAS 的语义里,一个空矩阵不是被 0 填满,而是根本没有元素。如果你显式写入一个 0,它仍然是一个"存在的元素",在结构 mask 里是会参与判断的。这个细节如果不理解,很多算法会出莫名其妙的问题。

好,说了这么多,来聊聊工程上的实操。GraphBLAS 在数据库里的落地,目前最成熟的方案之一是 OneSparse,这是一个 PostgreSQL 扩展。它把 GraphBLAS 的矩阵、向量、半环包装成了 SQL 的类型和函数。你可以在 PostgreSQL 里直接写这样的 SQL——用 matrix_query 从一个边表构造邻接矩阵,然后调用 mxm 或者 mxv 做矩阵乘法,或者直接调 bfs、sssp、pagerank 这些封装好的图算法。

不过 matrix_query 这个入口有个前提:它要求节点主键映射成连续的非负整数下标。GraphBLAS 本身的 API 只认整数下标,不理解业务主键是什么。所以如果你手里的是一个 UUID 类型的用户 ID,必须先建立一张映射表,把 UUID 转成 0、1、2、3 这样的整数下标。而且这个映射必须可重建、可审计,因为图算法返回的都是下标,最后还要能 join 回原表转换成业务主键,否则结果没法解释。

这里还有一个工程上的问题:大矩阵在 PostgreSQL 里是作为一个单一值存储的,它会走 TOAST,会受 MVCC 影响。一个大矩阵值的更新,不是"小更新"——它会膨胀 MVCC 版本,会影响备份和复制的体积。所以在 DBA 层面,一定要关注对象大小和资源隔离。

总结一下我的看法。GraphBLAS 最有价值的地方,是把一批图算法——BFS、最短路劲、PageRank、三角计数、连通分量——统一到稀疏矩阵内核,让这些算法可以复用底层的存储格式选择和并行优化。如果你面临的正是这类批量图分析问题,并且在 PostgreSQL 生态里已经有大量关系数据,GraphBLAS 值得评估。

但如果你的团队只熟悉 SQL,对 semiring、mask、descriptor 这些概念有抗拒心理,或者业务的路径查询主要是复杂属性模式匹配,那 GraphBLAS 的学习曲线可能不是必要的投入。属性图模型和 Cypher 在这些场景里更直接。

技术选型这种东西,从来不是"哪个更好",而是"哪个更适合这个团队、这个阶段、这个业务"。记住这句话,能少踩很多坑。