tva
← Insights

关系计算的闭包表

邻接列表的限制

大多数树状结构首先使用邻接列表建模:每行存储 parent_id。这对于直接的父子关系很好,但对于需要遍历多代的查询来说很慢:"找到这个人的所有后代"需要递归查询,而"这两个人是什么关系?"需要从两端遍历。

闭包表结构

闭包表存储每对祖先-后代关系以及它们之间的距离:

CREATE TABLE family_closure (
  ancestor_id   TEXT,
  descendant_id TEXT,
  depth         INTEGER,
  PRIMARY KEY (ancestor_id, descendant_id)
);

每个人与自己有一行(depth=0),与其父母有一行(depth=1),与其祖父母有一行(depth=2),依此类推。

查询模式

查找所有后代(任意深度):

SELECT descendant_id FROM family_closure
WHERE ancestor_id = :person_id AND depth > 0

检查两人是否有亲属关系:

SELECT COUNT(*) > 0 FROM family_closure a
JOIN family_closure b ON a.ancestor_id = b.ancestor_id
WHERE a.descendant_id = :person_a AND b.descendant_id = :person_b

维护闭包表

当添加一个新人时,必须插入包含其所有祖先的闭包行。这通常通过数据库触发器或应用层事务来处理:插入个人,然后从其父节点的现有闭包行中插入闭包行。

闭包表的读写权衡非常适合读多写少的家谱:每次添加都比邻接列表慢,但查询要快得多。

相关洞见

相关文章