【问题标题】:Table design for an ordered tree with composite keys具有复合键的有序树的表设计
【发布时间】:2016-04-06 07:10:50
【问题描述】:

在考虑数据库规范化规则时首选哪种表设计:

考虑以下用于描述有序树的节点表的设计。键是复合键。

  • ck:复合键
  • parent:父节点
  • next:下一个节点,其中next.parent = parent.
    (这定义了一个前向链表)
  • sk:代理键

设计1:

node(ck_x, ck_y, parent_ck_x, parent_ck_y, next_ck_x, next_ck_y)

设计2:

node(sk, ck_x, ck_y, parent_ck_x, parent_ck_y, next_ck_x, next_ck_y)

设计 3:

node(sk, ck_x, ck_y, parent_sk, next_sk)

第一个设计有 6 列。第二种设计增加了一个替代键,有 7 个列。第三种设计有 5 个列,它使用代理项来保存一列。

是否有任何规范化规则(或其他数据库设计规则)偏好一种设计而不是其他设计?

更新

替代设计:子类型节点表、isParent 标志、嵌套集。这些设计具有更大的读/写复杂性。

设计 4:

  • 此设计将表拆分为 3 个表。父表和下一个表包含来自节点表的键的互斥子集。它为每个节点使用2+4=6 列。

    node(ck_x, ck_y)

    parent(ck_x, ck_y, parent_ck_x, parent_ck_y)

    next(ck_x, ck_y, next_ck_x, next_ck_y)

设计 5:

  • 此设计使用 isParent 标志来指示下一项是父项。它使用4+1=5 列,1 列只是一点点。这比设计 3) 中使用的 5 列空间小

    node(ck_x, ck_y, next_ck_x, next_ck_y, isParent)

设计 6:

  • 此设计使用嵌套集来创建有序树。复合键不再用于定义父级或子级的顺序。它使用2+2=4 列。但是下限列和上限列都应该使用sizeof(ck_x)+sizeof(ck_y),这等于设计1中使用的6列的空间。

    node(ck_x, ck_y, lowerBound, upperBound)

更新

设计 7:

  • 这使用索引来表示节点的位置。

    node(ck_x, ck_y, parent_ck_x, parent_ck_y, index)

备注

  • 使用前一个节点 i.s.o.与插入和更新相比,下一个节点减少了对单个插入的创建和添加。

  • 规范化与列或表的数量无关。

【问题讨论】:

  • 请为每个表提供一个由列名参数化的语句,其中的一行表示树。
  • 通常您想将链表嵌入到关系设计中。存储顺序的首选方法是分配一个 ordering-key,其值指示组内兄弟姐妹的顺序。虽然这确实需要将键重新分配给组内的所有兄弟姐妹,但考虑到关系查询的实际工作方式,这更可取。
  • 谢谢。问题是当使用 next 时,父信息有点重复,因为我们已经知道第一个兄弟的父信息。使用序数位置删除此重复项,因为除了通过父项之外无法找到兄弟姐妹。我担心的是,使用下一个指针这在某种程度上不符合规范化形式(指导线)。使用序数可以解决这个问题,但它不能回答我的问题。给定一个使用下一个指针的数据库?是否符合 1 2 3 4 5 6 NF?是否有任何使用下一个指针违反的设计指南。设计 6 有点类似。

标签: database database-normalization composite-key surrogate-key


【解决方案1】:

TL;DR 根据您提供给我们的内容进行猜测:根据可能的功能依赖关系(确定候选键)以及您似乎如何表示树,所有这些设计都在 5NF 中。这里的设计不需要因为标准化而改变。


规范化用其他表替换一个表而不引入新列。对 BCNF 的规范化需要了解所有的函数依赖关系;除此之外的规范化需要了解连接依赖关系。这需要通过在表格中了解行对情况的说明以及可能出现的情况。 (如果我们知道某些列是唯一的,那么我们就知道它们在功能上决定了所有列。)

首先选择可以描述可能出现的任何情况并表达对这些情况的查询的设计。规范化可能会改进设计(在减少更新异常或某些冗余方面),但设计的适当性或质量的其他方面与规范化无关。必须谨慎选择树结构关系设计,以适应预期用途和 DBMS 特性。

PS 1 规范化不引入代理项。功能依赖很重要;你没有给他们。候选键很重要;你没有给他们。 (主键仅在它们是候选键时才重要。)阅读规范化的基本概念和步骤。

PS 2 规范化未解决对共享同一父级的链表兄弟的约束。仅仅因为有重复的,就不需要冗余;冗余是关于 rows 在表中或不在表中重复的语句Re "redundancy". 事实上,描述树的显而易见的基本关系方式只是一张表“父 P 有子 C”或“父 P 有第 N 个子 C”。您正在以关系方式表示一棵。不要以关系方式表示树的(非关系)表示

PS 3 您对列的数量和大小/空间(包括代理键的使用)的关注几乎肯定是错误的。只需根据您的查询和更新进行最直接的设计即可。 (同样,你没有描述。)

【讨论】:

  • 所以规范化不需要引入代理键来删除列,因为对主键没有功能依赖?但我们确实知道存在某种依赖关系,因为下一项仅限于父项相同的项。也许 parent(ck_x, ck_y, parent_ck_x, parent_ck_y), next(ck_x, ck_y, next_ck_x, next_ck_y) 定义了更高的归一化形式?
  • @Wouter:规范化绝对不是关于引入代理键。
  • 感谢 PS2 回答了我的问题。虽然它看起来仍然像冗余。它与规范化无关。
  • @Wouter 我在我的回答中添加了一个链接,以回答有关重复值与冗余的答案。
  • 谢谢。我正在考虑的冗余是有关具有相同父母的兄弟姐妹的信息。在某种程度上,如果您知道父母是兄弟姐妹,那么您已经知道父母。归一化(2,3 和 BCNF)也处理冗余。我的设计 4 和 5 只存储一次。但是找到任何节点的父节点需要递归查询。设计 6 不需要递归查询并使用边界来存储递归。 (但更新查询也会变得更复杂。)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-10-04
  • 2018-07-11
  • 1970-01-01
  • 2013-04-30
  • 2018-11-22
  • 1970-01-01
  • 2015-04-10
相关资源
最近更新 更多