sql - 关系数据库设计是否适合存储这种复杂结构
问题描述
TL;博士:
我想使用非关系设计将节点树存储在自引用表中,因为我们永远不需要关系选择数据子集。这允许极其简单的递归存储和检索功能。
同事想要使用关系设计来存储对象的每个特定字段——我假设是因为他相信关系总是更好。(他没有任何具体原因)这将需要更多的表和更复杂的存储和检索功能,我认为这对我们没有任何好处。
这两种设计方法是否有任何特定的好处或缺陷?
树通常如何存储在数据库中?自引用表?
是否有任何已知的存储在数据库中的数据树样本可能与我们试图解决的任务相吻合?
在工作中,我们使用复杂的结构来描述一个对象,很遗憾,由于工作限制,我无法分享确切的结构,但我将给出一个等效的结构示例并解释它的特点。
该结构可以用 json 表示,但实际上符合更严格的语法限制。
结构中有四种实体:
- 顶级节点
- 这个节点是一个json对象,必须是最顶层的json对象
- 该节点必须恰好包含 4 个属性(元信息 1 到 4)
- 此节点必须恰好包含 1 个“主”容器节点
- 容器节点
- 这些是包含其他容器和模式节点的 json 对象
- 必须包含 1 个名为“container_attribute”的属性
- 可能包含任意数量的其他容器和模式
- 模式节点
- 这些是包含 3 个属性的 json 对象
- 模式在技术上是一个容器
- 可能不包含任何其他内容
- 属性节点
- 这些只是 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"
}
}
}
}
我们想将这个结构存储在我们内部的办公室数据库中,我建议我们使用三个表,一个将所有 json 对象存储在一个自引用表中,一个将所有 json 字符串存储在一个引用 json 对象表的表中,然后是第三个表,用于将顶级容器与对象名称联系起来。
架构看起来像这样:
attibutes 表将用于存储所有 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)
);
容器表将用于将所有容器存储在自引用表中以创建“树”结构:
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
);
上述结构的好处是它提供了一个非常简单的递归函数来迭代树并存储属性和容器。
缺点是它不是任何关系,因此无助于执行复杂的关系查询来检索信息集。
我说我们应该使用它的原因是因为我们绝对没有理由以关系方式选择这些对象的片段,每个对象上的数据仅在该对象的上下文中有用,并且我们没有任何情况可以需要出于任何原因选择此数据,除了重建对象。
但是我的同事说我们应该使用关系数据库设计来存储它,并且每个“关键字”属性都应该有自己的表(容器关键字表、3 个模式关键字表、4 个顶级关键字表)。
结果是在建议的关系设计中存储这些对象变得更加复杂,并且需要更多的表。
请注意,查询速度/效率不是问题,因为此对象/数据库供内部使用,用于根本不对时间敏感的目的。最终,我们所做的只是创建新的“对象”并存储它们,然后查询数据库以重建所有对象。
如果关系数据库设计没有任何好处,那么是否有任何理由使用它而不是允许如此简单的存储/检索 API 的东西?
我建议的架构是否有任何重大问题?
解决方案
“我们永远不需要 X”是一个相当大胆的假设,事实证明它比你想象的更经常被证明是没有根据的。事实上,特别是对于树结构,最自然的需求是“放大一个节点”并将其在短时间内视为一棵树。
编辑
如果不清楚为什么这很重要:关系方法往往会提供更大的灵活性,因为这种灵活性内置于数据结构中。一旦需求开始演变,非关系方法(通常意味着一切都在代码中解决)往往会导致额外的代码修改。
推荐阅读
- android - 使用 Vuforia 从相机获取目标图像
- python - 在 Flask 和 Jinja2 中多次使用相同的模板名称
- javascript - 如何操作 Firebase 快照数据
- swift - 泛型类型“T”不符合协议“可编码”
- compiler-errors - 如果没有错误,我怎样才能只显示警告?
- python - 我使用 urllib.request 不断收到 HTTP 400 Bad Request 错误?
- javascript - 如何在另一个while循环中创建一个while循环?
- php - 需要帮助使用 php 实现多语言网站
- ocaml - 通过折叠将列表相乘
- java - Java - 如何在联系人列表中存储与某人相关的多个电话号码和关键字