我正在处理分层数据,如树结构。我想知道将它们存储在数据库中的最佳方式是什么。
我从 MySQL 中的邻接表开始。但随着数据的增加,性能似乎会下降。我有大约 20,000 行存储在具有父子关系的 MySQL 表中,并且将来还会增加。获取数据需要很长时间,因为我必须根据树的深度编写许多自连接。
所以我正在寻找存储此类数据的最佳方法。在一次地方,我发现嵌套集比邻接列表更好。然后我被建议考虑 NoSQL,如果这能解决我的问题。所以我现在很困惑是继续使用 SQL 还是进入 No SQL 或者是否有其他最好的方法来处理此类数据。
那么有人可以建议我什么是最好的方法吗?
如果 MySQL 给您带来的麻烦多于它解决的问题,我会考虑一下 MongoDB、CouchDB 或 ElasticSearch(取决于您的用例)。甚至可能是 Neo4j。您的选择应该归结为几个要点,例如复制、扩展能力、一致性……我建议您在做出决定之前仔细阅读一些官方文档。这是用于比较的起点。
采用 NoSQL 将摆脱所有连接并提高性能,但您仍然需要使用邻接列表、嵌套集、物化路径等来实现适当的层次结构......
请记住,上述 NoSQL 技术几乎都使用最终一致性,这本质上意味着您的数据在给定时间在某些节点之间可能不一致。如果这是一个问题,您应该坚持使用 RDBMS。
Postgres 对它有原生支持,使用
ltree
:
-- Ltree type presentation
-- Farshid Ashorui
-- First of all, this is an extension (included with standard installation)
CREATE EXTENSION IF NOT EXISTS ltree;
-- We need to specify `ltree` type.
CREATE TABLE IF NOT EXISTS tree(
id serial primary key,
letter char,
path ltree
);
-- we are using `gist` index for super fast indexing of the path.
-- read more here: http://patshaughnessy.net/2017/12/15/looking-inside-postgres-at-a-gist-index
-- This is Postgres’s GiST index API to find and match descendant nodes
CREATE INDEX IF NOT EXISTS tree_path_idx ON tree USING GIST (path);
-- @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
-- Root of heirarchy
insert into tree (letter, path) values ('A', 'A');
insert into tree (letter, path) values ('B', 'A.B');
-- Notice here, we are deviating
insert into tree (letter, path) values ('C', 'A.C');
insert into tree (letter, path) values ('D', 'A.C.D');
insert into tree (letter, path) values ('E', 'A.C.E');
insert into tree (letter, path) values ('F', 'A.C.F');
-- Back to B path
insert into tree (letter, path) values ('G', 'A.B.G');
-- @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
-- Search for A.C path
select * from tree where path <@ 'A.C';
-- More advanced one:
select * from tree where strpos(path::varchar, 'A.B.G') = 1;
您可以参考文章,其中讨论了处理分层数据的四种选项:
邻接列表
每个条目都知道其直接父条目
路径枚举
在每个节点中存储祖先链
嵌套集
每个条目都使用左右数字对其后代进行编码
关闭表
单独的表来管理祖先和后代的映射。