你可能知道有一个名为ltree的PostgreSQL模块.此外,您还可以使用数组类型作为整数(*1,请参阅下面的注释),在此测试中显示,与ltree相比,其递归查询实际上执行速度稍慢 - 除了字符串索引(*2,见下面的评论).
我不太确定这些测试结果的可信度.
这里我最大的问题实际上是关于相对未知的,几乎没有文档的树模块.这里描述(文档也可以找到!!)如下:
支持分层数据类型(类型的词典树),应该转到contrib/tree,因为缺少适当的文档而待决 .
阅读完文档后,我有点困惑,我是否应该以我的大应用程序为基础(一个CMS,一切都将存储在一个层次结构树结构中 - 不仅是内容,还有文件等,所以你可以看到这快速扩展)在ltree,普通物化路径(Path Enumeration)周围用分隔字符串或整数数组作为路径 - 或者理论上相对未知的"树"模块应该是更快,更可扩展和更好的解决方案.
我已经分析了不同的树结构模型,由于查询性能,节点和子树的可伸缩性和重新排序是我的主要要求,我已经能够排除邻接列表(递归CTE不会解决性能,因为树缩放巨大),嵌套集/间隔(在一些查询中不够快,考虑到它在填充树时的缺点),闭包表(在复杂的树中非常大的缩放 - 对我这样的大型项目没有用)等等并决定采用物化路径,对于读取操作来说非常快,并且可以轻松地在子层次上移动子树和节点.所以问题只是关于物化路径的最佳建议实现.
我对在PostgreSQL中听到你对"树"的理论或经验感到特别好奇.
我具有使用PostgreSQL的ltree模块构建的这种物化路径树结构。
我当然可以轻松地使用ltree从整棵树或特定路径/子路径中获取所有节点,但是当我这样做时,自然地,我得到的是很多行(等于节点中的节点的数组/切片)结束.. Golang /您使用的任何编程语言)
我要做的是将树(理想情况下是从某个起点和终点的路径/点)作为树状JSON树对象等来获取
{
"id": 1,
"path": "1",
"name": "root",
"children": [
{
"id": 2,
"path": "1.2",
"name": "Node 2",
"children": [
{
"id": 3,
"path": "1.2.3",
"name": "Node 3",
"children": [
{
"id": 4,
"path": "1.2.3.4",
"name": "Node 4",
"children": [
]
}
]
},
{
"id": 5,
"path": "1.2.5",
"name": "Node 5",
"children": [
]
}
]
}
]
}
Run Code Online (Sandbox Code Playgroud)
我从线性(非分层)行/数组/切片结果集中知道,我当然可以在Golang中进行分解,并在其中进行创建此json的必要业务逻辑,但是如果有方便的话,肯定会好得多直接通过PostgreSQL实现此目标的方法。
那么,您如何在PostgreSQL中将ltree树形结构输出到json-从起始路径到结束路径都集中地?
如果您不知道ltree,我想这个问题可能会进一步推广到“分层路径树到分层json”
我也在考虑在ltree路径之外的所有节点上添加一个parent_id的想法,因为至少那样我就可以使用使用该id的递归调用来获取我猜的json ...我也考虑过根据父ID的更改发生时间在该parent_id上放置触发器以管理路径(保持更新)-我知道这是另一个问题,但是也许您也可以告诉我您的观点,对此吗?
我希望有一些天才可以帮助我。:)
为了方便起见,这里有一个示例创建脚本,可用于节省时间:
CREATE TABLE node …Run Code Online (Sandbox Code Playgroud) 我有一个带有ltree路径列的表.在我的层次结构中,标签的路径是唯一的,这意味着每个标签都只有一个父标签.换句话说,表中没有两个以相同标签结尾的ltree路径.
我有一个ltree标签,让我们说"C".
我可以使用以下查询找到此标签的所有后代行:
select * from myTree where path ~ '*.C.*';
Run Code Online (Sandbox Code Playgroud)
这工作正常,并提供正确的子树.
现在我需要实现查询以查找此给定标签的所有祖先行.我的意思是如果表中有3行标有"A","AB","ABC",我想得到路径为"A"和"AB"的行(可能包括"ABC"本身,现在没关系).
如果我知道"C"的完整路径(上例中的"ABC"),则@>操作员可以轻松完成任务.但是,现在我只知道"C",我仍然希望通过单个查询来完成任务.有没有办法做到这一点?
我有3张桌子:
位置,位置描述,其中包含每个位置等的语言以及1用于商店的语言。
位置描述表也将层次结构保存在ltree路径字段中,如下所示:
city.district1
city.district1.area1
city.district1.area2
...
city.district2.area1
city.district2.area2
...
city(n).district(n).area(n)
Run Code Online (Sandbox Code Playgroud)
STORE表包含一个外键location_id,以引用其所属的位置。
因此,我想做的是获取带有每个节点的存储数的树,并按此树排序。
例如:
city.district3 (10)
city.district3.area2 (6)
city.district3.area1 (4)
...
city.district2 (9)
city.district2.area1 (5)
city.district2.area3 (3)
city.district2.area2 (1)
...
city.districtN (5)
city.districtN.area2 (3)
city.districtN.area1 (2)
Run Code Online (Sandbox Code Playgroud)
到目前为止,我所做的只是获取树和计数(存储),但仅针对区域而非区域,并且没有想要的顺序。
SELECT locdesc.title, COUNT(store.store_id) as totalStores, locdesc.path, nlevel(locdesc.path) as lvl
FROM st_location loc
JOIN st_location_desc locdesc ON locdesc.location_id = loc.location_id
LEFT JOIN st_store store ON store.location_id = loc.location_id
WHERE path ~ 'london.*{1,2}'
GROUP BY locdesc.path, locdesc.title
ORDER BY path
Run Code Online (Sandbox Code Playgroud)
================================================== =============================== EDIT1:
更新了我的查询,我得到了父母和孩子的总计记录(我相信有一种更有效的方法)。我仍然缺少订单:
SELECT …Run Code Online (Sandbox Code Playgroud) 如标题所示,我很难过,猜测如何才能有效地更新多行中的值。该列通过data-type实现ltree。因此,在postgresql以下示例中,应对此数据类型进行某种形式的特殊操作:
假设表product_sections的名称为:包含这些值的列的名称为section_path (type: ltree)
Android
Android.Browser
Android.Browser.Test
Android.Browser.Compare.URL
Run Code Online (Sandbox Code Playgroud)
在这里,我只想将其更新Browser为类似Foopart的数据,这样数据将变为:
Android
Android.Foo
Android.Foo.Test
Android.Foo.Compare.URL
Run Code Online (Sandbox Code Playgroud)
提前致谢 :)
Materialized Path is a method for representing hierarchy in SQL. Each node contains the path itself and all its ancestors (grandparent/parent/self).
The django-treebeard implementation of MP (docs):
Each step of the path is a fixed length for consistent performance.
Each node contains depth and numchild fields (fast reads at minimal cost to writes).
The path field is indexed (with a standard b-tree index):
The materialized path approach makes heavy use of LIKE in your database, with …
我使用 Postgres 中的 ltree 扩展来管理树的路径。我想确保名称字段对于树上的任何给定路径都是唯一的。我可以使用约束来完成此操作还是必须将其构建到查询中?
demo table
------------------------------
| name (text) | path (ltree) |
------------------------------
| a | 1 |
------------------------------
| b | 1.2 |
------------------------------
| b | 1.3 |
------------------------------
| b | 1.2.4 | <-- this should fail on insert
------------------------------
Run Code Online (Sandbox Code Playgroud)
如果我必须将其构建到查询中,如果我使用 READ COMMITTED,这是否可能存在竞争条件?
CREATE TABLE demo (
name text NOT null,
path ltree NOT null
);
CREATE INDEX path_gist_idx ON demo USING GIST (path);
INSERT INTO demo (name, path)
SELECT 'a', '1'
WHERE NOT …Run Code Online (Sandbox Code Playgroud) 因为我使用的是 PostgreSQL,所以有一个名为ltree的模块的模块,它至少满足我的一个需求,性能(我不知道可扩展性?有人说物化路径树不能很好地扩展..)。
由于我正在开发的应用程序是一个完全围绕大树、节点、子树等构建的 CMS,因此对这些节点进行排队的性能绝对重要,但由于它是一个分层的大型(随着它的增长)树,您正在处理和操作GUI(CRUD),我还希望用户能够拖放以重新排序节点、子树等,同时正确更新数据库中的树(子记录)。
据我了解,在树中移动和重新排序节点/子树并不是 ltree/物化路径树真正的优点,所以我希望您能提供帮助,要么向我指出最好的正确树结构模型为了性能和移动子树和节点,或者也许......如果 ltree 确实不是过去的遗留物但仍然值得使用,那么如何使用 PostgreSQL 的 ltree 模块实现这一点?在这种情况下为什么/为什么不使用ltree?
要求:
我还在考虑闭包表,又名桥表(很多!),嵌套间隔(不确定我到底理解如何实现它,并且当前没有好的示例或要点?)或 B 树模型。我只是还不太确定,这些将如何满足我的上述 4 个要求。在嵌套间隔中重新组织子树和节点似乎很简单,而且性能似乎不错。很难选择合适的。
因为我确实需要性能(查询/读取性能)、可扩展性、排序,所以我有点认为带有排序顺序的闭包表可能非常接近,但我无法想象闭包表和磁盘空间开销将变得有多大,就像我的树一样并且节点变大。闭包表和可扩展性,我只是不太确定。我担心这个问题是错误的吗?这项任务的最佳解决方案是什么?
我一直在使用 Postgresltree构造来存储层次结构。现在,我想收集树中的所有叶节点。有没有一个简单的机制来做到这一点?
CREATE TABLE foo
AS
SELECT node::ltree
FROM ( VALUES
('Top.Astronomy'),
('Top.Astronomy.Astrophysics'),
('Top.Pictures'),
('Top.Pictures.Stars')
) AS t(node);
Run Code Online (Sandbox Code Playgroud)
我如何返回
Top.Astronomy.Astrophysics
Top.Pictures.Stars
Run Code Online (Sandbox Code Playgroud) 我想在 PostgreSQL 数据库中存储分层数据。我找到了 ltree 扩展,但它用于存储树结构数据,即只能有一个父节点。有什么方法可以调整它来存储多个父节点吗?