AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / dba / 问题 / 314769
Accepted
Lance
Lance
Asked: 2022-07-24 10:12:43 +0800 CST2022-07-24 10:12:43 +0800 CST 2022-07-24 10:12:43 +0800 CST

如何实现/构建可以处理具有许多可选属性的类型/表的 SQL 数据库模式?

  • 772

我正在研究一个精简的数据库模式(在 PostgreSQL 中),比如旧的FreeBase,只是没有那么多东西。到目前为止大约有 100 张桌子,但那是在我考虑为特殊情况添加几十张之前,感觉不太对劲。让我用一个简化的例子来解释这个问题,它以一种小的方式复制了这个问题,想象一下它会变得更加复杂,一个表有几十个可选的属性/关系/关联,并且有许多像这样的不同的互连表。

我知道并广泛使用过像 MongoDB 这样的 NoSQL 文档数据库,并且在像 Neo4j 这样的图形数据库中涉足过。由于这个副项目的复杂性,它们是我宁愿避免使用的工具,而且用于部署的工具和资源与当今世界的 PostgreSQL 之类的东西不一样。

因此,为了说明这个问题,想象一个“符号”表,其中包含所有unicode符号,以及 unicode 范围之外的数千个符号(征兵、玛雅脚本、其他非脚本符号等)。基表如下所示:

table symbols {
  id
  unicode (optional)
  preview_image_url (optional)
  title
  description
}

我们已经有了一些可选属性,因为有些符号没有 unicode,有些不需要预览图像(所有 unicode 都可以在浏览器中呈现,等等)。但是,让我们考虑一下我们想要存储有关...的结构化信息的其他一些“类型”符号。

首先,我们可以想到“脚本”符号,即用于书写系统的符号。很酷,我们可以在我们的表中添加可选的“script_name”属性,这还不错。但是不,什么样的脚本符号?有从右到左的文字、垂直文字、表意文字、字母文字、abjads 和 abugidas 等。一些字母文字如拉丁文字有镜像符号(如括号)或大写/小写对。一些脚本将字符与特定规则组合在一起,这些规则可以与哪些组合。有些符号纯粹是装饰性的,有些是几何的。因此,我们尝试考虑所有这些可选功能:

table symbols {
  id
  unicode (optional)
  preview_image_url (optional)
  title
  description
  is_logographic (optional)
  is_vertical (optional)
  is_rtl (optional)
  is_alphabet (optional)
  is_abjad (optional)
  is_abugida (optional)
  script_name (optional)
  mirror_image_symbol_id (optional)
  uppercase_symbol_id (optional)
  lowercase_symbol_id (optional)
  combining_class (optional)
}

不过,有些人可能会说拥有所有这些可选属性还不错,我不知道。

然后您可以继续并添加更多子子类型....

  • 类似三角形的符号(在 unicode 中有一些)
  • 阴影三角形符号
  • 空三角形符号

想象一下你可以尝试在谷歌上搜索与符号相关的所有可能的东西。

  • 看起来像“c”的符号
    • ©(版权符号)
    • ?(版权符号)
    • ℃(摄氏度的符号)
    • ¢(美元的美分符号)
    • ₡(哥斯达黎加和萨尔瓦多货币冒号的符号)
    • ₵(塞地符号,加纳货币)
    • ₢(克鲁塞罗的符号,巴西的历史货币)
    • ℄(实际上是“cl”
  • 带有内置组合标记的符号,如 é。
  • 1 字节的 Unicode 字形
  • 2 字节 unicode 字形
  • 4字节...
  • ...

它开始变成这样:

table symbols {
  id
  unicode (optional)
  preview_image_url (optional)
  title
  description
  is_logographic (optional)
  is_vertical (optional)
  is_rtl (optional)
  is_alphabet (optional)
  is_abjad (optional)
  is_abugida (optional)
  script_name (optional)
  mirror_image_symbol_id (optional)
  uppercase_symbol_id (optional)
  lowercase_symbol_id (optional)
  combining_class (optional)
  is_triangle_like (optional)
  is_shaded_triangle_like (optional)
  is_empty_triangle_like (optional)
  looks_like_c (optional)
  looks_like_d (optional)
  looks_like_l (optional)
  ...
  has_built_in_diacritic (optional)
  is_1_byte (optional)
  is_2_bytes (optional)
  ...
}

很快我们就会得到 50 或 100 个可选字段。当您尝试对“生物体”及其所有独特而多样的特征进行建模时,您可以想象这会变得更加复杂!数以千计的可选功能,并且没有明确的 OO 类层次结构来创建子类,它更像是一个互连组合的图/网络。

所以我的想法开始转向让事情变得超级抽象/通用,并创建一个名为“facts”的表格,比如:

table facts {
  id
  object_type
  object_id
  property_name
  value_type
  value_id
}

这样你就可以创建一个像“symbol a”这样的对象,并在它上面有“facts”,比如“属性名称是script_name,值类型是一个字符串表,其中一个字符串映射到一个ID,作为对象符号类型的属性” . 或者另一个事实是:

// facts table
id: 123
object_type: 'symbol'
object_id: 12321
property_name: 'is_1_byte'
value_type: 'boolean'
value_id: 444

// boolean table
id: 444
value: true

// symbol table
id: 12321
unicode: 'a'

但是沿着这条路走下去,你最终只会得到几个表(基本上是“事实”表,可能还有 1 或 2 个其他元表),而不是 100 个。但是事情变得更加难以思考和可视化,并且查询变得更复杂一些。

但我看不到解决这个问题的方法。我倾向于让数据库成为这种抽象类型的“事实”表,但是在应用程序层中让它看起来更面向对象,就像在 JavaScript 中一样,它有属性或没有属性。我想稍微“强化”一下,并给每个组合/变体一个不同的类型名称,但这并不完全奏效,例如:

{
  type: 'alphabet_symbol',
  value: 'e'
},
{
  type: 'geometric_symbol',
  value: '▲'
}

然后构建一个类型树:

symbol
  alphabet_symbol
    mirror_image_alphabet_symbol
      mirror_image_alphabet_symbol_with_capital_lowercase
      capital_lowercase_alphabet_symbol
  abjad_symbol
  geometric_symbol
    triangle_geometric_symbol
      shaded_triangle_geometric_symbol

但这打破了:

symbol
  alphabet_symbol
    (cyrillic б)
  look_like_6_symbol
    (cyrillic б)

所以就像,也许只是向中心对象添加标签。

б
  id: 455

tags
  - name: 'is_alphabet_symbol'
    symbol_id: 455
  - name: 'looks_like_6_symbol'
    symbol_id: 455

但在这一点上,它归结为我最初在您开始尝试处理更多案件时分享的通用/抽象“事实”想法。

// facts table
id: 124
object_type: 'symbol'
object_id: 455
property_name: 'is_alphabet_symbol'
value_type: 'boolean'
value_id: 444

// boolean table
id: 444
value: true

// symbol table
id: 455
unicode: 'б'

所以想知道,这里简要概述的处理“类型”的动态性和变化的推荐方法是什么?您如何平衡捕获尽可能多的结构化数据的愿望而不制作一个大的可选填充平面表(这似乎在几十个可选列之后分解,更不用说在有机体建模的情况下为 100 或 1000) .

database-design schema
  • 2 2 个回答
  • 97 Views

2 个回答

  • Voted
  1. David Browne - Microsoft
    2022-07-24T12:08:24+08:002022-07-24T12:08:24+08:00

    通常,您拒绝向模型添加如此多的属性,并规范化模型。对于每个属性,请询问 1) 是否真的需要添加到您的数据模型中,以及 2) 它是否真的属于该实体的属性,或者您是否应该向模型中引入新的子类型或引用实体。

    例如is_rtl,可能应该是相关Alphabet实体的属性,looks_like_d应该在单独的链接表中建模,并且is_shaded_triangle_like可能不值得添加到数据模型中。

    因此模型从单个表演变为适当的模型,例如:

    Symbol
      AlphabetSymbol
    Alphabet
    SybolLooksLikeSymbol
    Shape
    SymbolLooksLikeShape
    SymbolUpperCaseOfSymbol
    
    • 3
  2. Best Answer
    J.D.
    2022-07-24T16:16:54+08:002022-07-24T16:16:54+08:00

    抽象数据库层是一个很常见的想法,但这样做会丢失数据库系统的很多关系方面(令人惊讶的是,这在关系数据库管理系统中并不是一个好主意)。这被称为EAV 反模式,通常应该避免有几个原因,其中一些包括查询的复杂性增加,正如您所注意到的,还有一些是性能问题。

    在您的数据对象上拥有可为空的属性并不是世界末日,即使这会导致很多列。在 ERP 系统的数据库中看到这种情况并不少见,这些数据库通常有数千到数十万个表,有些每个表有几百到数千列。但这也不是最好的设计。

    正如大卫所说,更好的解决方案是规范化您的数据对象。考虑它的一个好方法是重构除对象表示的每个(或大多数)记录共有的核心属性之外的任何内容。将其他相关属性分组到自己的表中。这确实可能会导致更多的表,但如前所述,许多表在功能上没有任何问题。当然,维护工作量更大,但这是对适当设计的关系模式的权衡,有利于提高性能(否则本身可能需要大量工作)、改进的相关性以及改进的数据管理和准确性。

    • 2

相关问题

  • 过滤索引是否有助于改进基于输入时间的查询,还是应该避免这种情况?

  • MySQL VARCHAR 和 TEXT 数据类型有什么区别?

  • 存储计算值或根据要求重新计算它们更好吗?[复制]

  • 存储与计算聚合值

  • 在数据仓库中实现多对多关系有哪些方法?

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    连接到 PostgreSQL 服务器:致命:主机没有 pg_hba.conf 条目

    • 12 个回答
  • Marko Smith

    如何让sqlplus的输出出现在一行中?

    • 3 个回答
  • Marko Smith

    选择具有最大日期或最晚日期的日期

    • 3 个回答
  • Marko Smith

    如何列出 PostgreSQL 中的所有模式?

    • 4 个回答
  • Marko Smith

    列出指定表的所有列

    • 5 个回答
  • Marko Smith

    如何在不修改我自己的 tnsnames.ora 的情况下使用 sqlplus 连接到位于另一台主机上的 Oracle 数据库

    • 4 个回答
  • Marko Smith

    你如何mysqldump特定的表?

    • 4 个回答
  • Marko Smith

    使用 psql 列出数据库权限

    • 10 个回答
  • Marko Smith

    如何从 PostgreSQL 中的选择查询中将值插入表中?

    • 4 个回答
  • Marko Smith

    如何使用 psql 列出所有数据库和表?

    • 7 个回答
  • Martin Hope
    Jin 连接到 PostgreSQL 服务器:致命:主机没有 pg_hba.conf 条目 2014-12-02 02:54:58 +0800 CST
  • Martin Hope
    Stéphane 如何列出 PostgreSQL 中的所有模式? 2013-04-16 11:19:16 +0800 CST
  • Martin Hope
    Mike Walsh 为什么事务日志不断增长或空间不足? 2012-12-05 18:11:22 +0800 CST
  • Martin Hope
    Stephane Rolland 列出指定表的所有列 2012-08-14 04:44:44 +0800 CST
  • Martin Hope
    haxney MySQL 能否合理地对数十亿行执行查询? 2012-07-03 11:36:13 +0800 CST
  • Martin Hope
    qazwsx 如何监控大型 .sql 文件的导入进度? 2012-05-03 08:54:41 +0800 CST
  • Martin Hope
    markdorison 你如何mysqldump特定的表? 2011-12-17 12:39:37 +0800 CST
  • Martin Hope
    Jonas 如何使用 psql 对 SQL 查询进行计时? 2011-06-04 02:22:54 +0800 CST
  • Martin Hope
    Jonas 如何从 PostgreSQL 中的选择查询中将值插入表中? 2011-05-28 00:33:05 +0800 CST
  • Martin Hope
    Jonas 如何使用 psql 列出所有数据库和表? 2011-02-18 00:45:49 +0800 CST

热门标签

sql-server mysql postgresql sql-server-2014 sql-server-2016 oracle sql-server-2008 database-design query-performance sql-server-2017

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve