关系数据库设计是否适合存储这种复杂结构
Is A Relational Database Design Correct For Storing This Complex Structure
长话短说:
我想使用非关系设计在自引用 table 中存储节点树,因为我们永远不需要关系 select 数据子集。这允许极其简单的递归存储和检索功能。
同事想使用关系设计来存储对象的每个特定字段——我假设是因为他相信关系总是更好。 (他没有任何具体原因)这将需要更多的table和更复杂的存储和检索功能,我认为这对我们没有任何好处。
这两种设计方法有什么具体的好处或缺陷吗?
树木通常如何存储在数据库中?自引用 tables?
是否有任何已知的数据树样本存储在数据库中,这些样本可能与我们试图解决的任务一致?
在工作中,我们使用复杂的结构来描述一个对象,不幸的是,由于工作限制,我不能分享确切的结构,但我会给出一个等效的结构示例并解释它的特点。
结构可以用 json 表示,但实际上符合更严格的语法限制。
结构中有四种实体:
- 顶级节点
- 这个节点是一个json对象,它必须是顶级json对象
- 此节点必须恰好包含 4 个属性(元信息 1 到 4)
- 此节点必须恰好包含 1 个 'main' 容器节点
- 容器节点
- 这些 json 个包含其他容器和模式节点的对象
- 必须恰好包含 1 个名为 'container_attribute'
的属性
- 可能包含任意数量的其他容器和模式
- 模式节点
- 这些 json 个对象恰好包含 3 个属性
- 模式在技术上是一个容器
- 可能不包含任何其他内容
- 属性节点
- 这些只是 json 个字符串对象
顶级容器始终是一个 json 对象,包含 4 个属性和恰好 1 个名为 'main_container'
的容器
所有容器必须包含一个名为 'container_attribute' 的属性。
所有模式必须恰好包含三个属性
json 中的结构示例如下所示:
{
"top_level_node": {
"meta_info_1": "meta_info_keyword1",
"meta_info_2": "meta_info_keyword2",
"meta_info_3": "meta_info_keyword3",
"meta_info_4": "unique string of data",
"main_container": {
"container_attribute": "container_attribute_keyword",
"sub_container_1": {
"container_attribute": "container_attribute_keyword",
"pattern_1": {
"pattern_property_1": "pattern_property_1_keyword",
"pattern_property_2": "pattern_property_2_keyword",
"pattern_property_3": "unique string of data"
},
"pattern_2": {
"pattern_property_1": "pattern_property_1_keyword",
"pattern_property_2": "pattern_property_2_keyword",
"pattern_property_3": "unique string of data"
}
},
"pattern_3": {
"pattern_property_1": "pattern_property_1_keyword",
"pattern_property_2": "pattern_property_2_keyword",
"pattern_property_3": "unique string of data"
}
}
}
}
我们想将这个结构存储在我们的内部办公室数据库中,我建议我们使用三个 table,一个将所有 json 对象存储在自引用 table 和一个将所有 json 字符串存储在引用 json 对象 table 的 table 中,然后第三个 table 将顶级容器绑定到对象名称。
架构看起来像这样:
其中属性 table 将用于存储所有 json 字符串并引用父容器 ID:
CREATE TABLE attributes (
id int DEFAULT nextval('attributes_id_seq'::text),
name varchar(255),
container_id int,
type int,
value_type int,
value varchar(255)
);
容器 table 将用于将所有容器存储在自引用 table 中以创建 'tree' 结构:
CREATE TABLE containers (
id int DEFAULT nextval('containers_id_seq'::text),
parent_container_id int
);
然后是指向对象顶级容器 ID 的单个对象名称列表:
CREATE TABLE object_names (
id int DEFAULT nextval('object_names_id_seq'::text),
name varchar(255),
container_id int
);
上述结构的优点在于它提供了一个非常简单的递归函数来迭代树并存储属性和容器。
缺点是它不是关系型的,因此无助于执行复杂的关系查询来检索信息集。
我说我们应该使用它的原因是因为我们绝对没有理由以关系方式 select 这些对象的片段,每个对象上的数据仅在该对象的上下文中有用,并且除了重建对象之外,我们没有任何情况需要 select 这些数据。
但是我的同事说我们应该使用关系数据库设计来存储它,并且每个 'keyword' 属性都应该有自己的 table(容器关键字 table, 3 个模式关键字 tables, 4 个顶级关键字 tables)。
结果是在建议的关系设计中存储这些对象变得更加复杂,需要更多的 tables。
请注意,查询 speed/efficiency 不是问题,因为此 object/database 仅供内部使用,完全不是时间敏感的目的。最终我们所做的就是创建新的 'objects' 并存储它们,然后查询数据库以重建所有对象。
如果关系数据库设计没有任何好处,那么有什么理由将它用于允许如此简单的东西 storage/retrieval API?
我建议的架构是否存在任何重大问题?
"we will never need to X" 是一个相当大胆的假设,但事实证明它比您想象的更频繁地没有根据。事实上,特别是对于树结构,最自然的要求是 "zoom into a node" 并在短时间内将其视为一棵独立的树。
编辑
如果不清楚为什么这很重要:关系方法往往会提供更多的灵活性,因为这种灵活性内置于数据结构中。一旦需求开始发展,非关系方法(通常意味着一切都在代码中解决)往往会导致额外的代码循环。
长话短说:
我想使用非关系设计在自引用 table 中存储节点树,因为我们永远不需要关系 select 数据子集。这允许极其简单的递归存储和检索功能。
同事想使用关系设计来存储对象的每个特定字段——我假设是因为他相信关系总是更好。 (他没有任何具体原因)这将需要更多的table和更复杂的存储和检索功能,我认为这对我们没有任何好处。
这两种设计方法有什么具体的好处或缺陷吗?
树木通常如何存储在数据库中?自引用 tables?
是否有任何已知的数据树样本存储在数据库中,这些样本可能与我们试图解决的任务一致?
在工作中,我们使用复杂的结构来描述一个对象,不幸的是,由于工作限制,我不能分享确切的结构,但我会给出一个等效的结构示例并解释它的特点。
结构可以用 json 表示,但实际上符合更严格的语法限制。
结构中有四种实体:
- 顶级节点
- 这个节点是一个json对象,它必须是顶级json对象
- 此节点必须恰好包含 4 个属性(元信息 1 到 4)
- 此节点必须恰好包含 1 个 'main' 容器节点
- 容器节点
- 这些 json 个包含其他容器和模式节点的对象
- 必须恰好包含 1 个名为 'container_attribute' 的属性
- 可能包含任意数量的其他容器和模式
- 模式节点
- 这些 json 个对象恰好包含 3 个属性
- 模式在技术上是一个容器
- 可能不包含任何其他内容
- 属性节点
- 这些只是 json 个字符串对象
顶级容器始终是一个 json 对象,包含 4 个属性和恰好 1 个名为 'main_container'
的容器所有容器必须包含一个名为 'container_attribute' 的属性。
所有模式必须恰好包含三个属性
json 中的结构示例如下所示:
{
"top_level_node": {
"meta_info_1": "meta_info_keyword1",
"meta_info_2": "meta_info_keyword2",
"meta_info_3": "meta_info_keyword3",
"meta_info_4": "unique string of data",
"main_container": {
"container_attribute": "container_attribute_keyword",
"sub_container_1": {
"container_attribute": "container_attribute_keyword",
"pattern_1": {
"pattern_property_1": "pattern_property_1_keyword",
"pattern_property_2": "pattern_property_2_keyword",
"pattern_property_3": "unique string of data"
},
"pattern_2": {
"pattern_property_1": "pattern_property_1_keyword",
"pattern_property_2": "pattern_property_2_keyword",
"pattern_property_3": "unique string of data"
}
},
"pattern_3": {
"pattern_property_1": "pattern_property_1_keyword",
"pattern_property_2": "pattern_property_2_keyword",
"pattern_property_3": "unique string of data"
}
}
}
}
我们想将这个结构存储在我们的内部办公室数据库中,我建议我们使用三个 table,一个将所有 json 对象存储在自引用 table 和一个将所有 json 字符串存储在引用 json 对象 table 的 table 中,然后第三个 table 将顶级容器绑定到对象名称。
架构看起来像这样:
其中属性 table 将用于存储所有 json 字符串并引用父容器 ID:
CREATE TABLE attributes (
id int DEFAULT nextval('attributes_id_seq'::text),
name varchar(255),
container_id int,
type int,
value_type int,
value varchar(255)
);
容器 table 将用于将所有容器存储在自引用 table 中以创建 'tree' 结构:
CREATE TABLE containers (
id int DEFAULT nextval('containers_id_seq'::text),
parent_container_id int
);
然后是指向对象顶级容器 ID 的单个对象名称列表:
CREATE TABLE object_names (
id int DEFAULT nextval('object_names_id_seq'::text),
name varchar(255),
container_id int
);
上述结构的优点在于它提供了一个非常简单的递归函数来迭代树并存储属性和容器。
缺点是它不是关系型的,因此无助于执行复杂的关系查询来检索信息集。
我说我们应该使用它的原因是因为我们绝对没有理由以关系方式 select 这些对象的片段,每个对象上的数据仅在该对象的上下文中有用,并且除了重建对象之外,我们没有任何情况需要 select 这些数据。
但是我的同事说我们应该使用关系数据库设计来存储它,并且每个 'keyword' 属性都应该有自己的 table(容器关键字 table, 3 个模式关键字 tables, 4 个顶级关键字 tables)。
结果是在建议的关系设计中存储这些对象变得更加复杂,需要更多的 tables。
请注意,查询 speed/efficiency 不是问题,因为此 object/database 仅供内部使用,完全不是时间敏感的目的。最终我们所做的就是创建新的 'objects' 并存储它们,然后查询数据库以重建所有对象。
如果关系数据库设计没有任何好处,那么有什么理由将它用于允许如此简单的东西 storage/retrieval API?
我建议的架构是否存在任何重大问题?
"we will never need to X" 是一个相当大胆的假设,但事实证明它比您想象的更频繁地没有根据。事实上,特别是对于树结构,最自然的要求是 "zoom into a node" 并在短时间内将其视为一棵独立的树。
编辑
如果不清楚为什么这很重要:关系方法往往会提供更多的灵活性,因为这种灵活性内置于数据结构中。一旦需求开始发展,非关系方法(通常意味着一切都在代码中解决)往往会导致额外的代码循环。