首页 > 解决方案 > 关系数据库设计是否适合存储这种复杂结构

问题描述

TL;博士:

我想使用非关系设计将节点树存储在自引用表中,因为我们永远不需要关系选择数据子集。这允许极其简单的递归存储和检索功能。

同事想要使用关系设计来存储对象的每个特定字段——我假设是因为他相信关系总是更好。(他没有任何具体原因)这将需要更多的表和更复杂的存储和检索功能,我认为这对我们没有任何好处。

这两种设计方法是否有任何特定的好处或缺陷?

树通常如何存储在数据库中?自引用表?

是否有任何已知的存储在数据库中的数据树样本可能与我们试图解决的任务相吻合?


在工作中,我们使用复杂的结构来描述一个对象,很遗憾,由于工作限制,我无法分享确切的结构,但我将给出一个等效的结构示例并解释它的特点。

该结构可以用 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 的东西?

我建议的架构是否有任何重大问题?

标签: sqljsondatabase-designrelational-databasenon-relational-database

解决方案


“我们永远不需要 X”是一个相当大胆的假设,事实证明它比你想象的更经常被证明是没有根据的。事实上,特别是对于树结构,最自然的需求是“放大一个节点”并将其在短时间内视为一棵树。

编辑

如果不清楚为什么这很重要:关系方法往往会提供更大的灵活性,因为这种灵活性内置于数据结构中。一旦需求开始演变,非关系方法(通常意味着一切都在代码中解决)往往会导致额外的代码修改。


推荐阅读