以最佳方式存储分层数据:NoSQL或SQL

时间:2014-05-14 06:14:23

标签: mysql hierarchical-data adjacency-list nested-sets nosql

我正在处理分层数据,就像在树结构中一样。我想知道将它们存储在数据库中的最佳方法是什么。

我从MySQL的邻接列表开始。但随着数据的增加,性能似乎有所下降。我有大约20,000行存储在具有父子关系的MySQL表中,并且将来会增加。获取数据需要很长时间,因为我必须根据树的深度编写许多自连接。

所以我一直在寻找存储这类数据的最佳方法。在同一个地方,我发现嵌套集比邻接列表更好。然后我被建议查看NoSQL,如果这可以解决我的问题。所以我现在很困惑是继续使用SQL还是进入No SQL,或者是否还有其他最佳方法来处理这类数据。

所以有人可以建议我最好的方法吗?

2 个答案:

答案 0 :(得分:4)

如果MySQL给你带来的麻烦比它解决的更多,我会看看MongoDB,CouchDB或ElasticSearch(取决于你的用例)。甚至可能是Neo4j。您的选择应该归结为几个点,例如复制,扩展能力,一致性......我建议您在决定之前仔细阅读一些官方文档。这是一个starting point用于比较。

Going NoSQL将摆脱所有连接并提高性能,但您仍需要使用邻接列表,嵌套集,物化路径等实现适当的层次结构......

请记住,NoSQL技术几乎都使用最终的一致性,这实际上意味着您的数据在某些节点的给定时间可能不一致。如果这是一个问题,你应该坚持使用RDBMS。

答案 1 :(得分:0)

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;