存储查找表id或纯数据之间的决定

时间:2008-12-20 06:35:25

标签: sql database normalization lookup

我发现这很多,我不确定接近它的最佳方式。

我的问题是如何在使用外键查找表或直接在请求它的表中使用查找表值之间做出决定,完全避免查找表关系。

要记住的要点:

  • 使用第二种方法 需要对所有人进行大规模更新 记录引用数据的记录 在查找表中更改。

  • 这是更重点 对于有很多的表 该列引用了许多查找 table.Therefore很多外国人 钥匙意味着很多 每次查询时都加入 表

  • 此数据将来自丢弃 下拉列表将被拉出 来自查找表。为了在重新加载时匹配数据,值必须位于现有列表中(与第一个点相关)。

这里有最佳做法,还是需要考虑的关键点?

7 个答案:

答案 0 :(得分:27)

您可以使用带有VARCHAR主键的查找表,并且主数据表在其列上使用FOREIGN KEY,并进行级联更新。

CREATE TABLE ColorLookup (
  color VARCHAR(20) PRIMARY KEY
);

CREATE TABLE ItemsWithColors (
  ...other columns...,
  color VARCHAR(20),
  FOREIGN KEY (color) REFERENCES ColorLookup(color)
    ON UPDATE CASCADE ON DELETE SET NULL
);

该解决方案具有以下优点:

  • 您可以查询主数据表中的颜色名称,而无需连接到查找表。
  • 尽管如此,颜色名称仍限于查找表中的颜色集。
  • 您可以通过查询查找表获取唯一颜色名称列表(即使主数据中当前没有使用任何颜色名称)。
  • 如果更改查找表中的颜色,则更改会自动级联到主数据表中的所有引用行。

令我惊讶的是,在这个问题上有这么多其他人似乎错误地认为“正常化”是什么。使用代理键(无处不在的“id”)与规范化无关!


来自@MacGruber的评论:

是的,尺寸是一个因素。例如,在InnoDB中,每个二级索引都存储发生给定索引值的行的主键值。因此,您拥有的二级索引越多,为主键使用“庞大”数据类型的开销就越大。

这也会影响外键;外键列必须与它引用的主键具有相同的数据类型。您可能有一个小的查找表,因此您认为50行表中的主键大小无关紧要。但该查找表可能被其他表中的数百万或数十亿行引用!

所有案件都没有正确答案。对于不同的情况,任何答案都是正确的。您只需了解权衡,并尝试根据具体情况做出明智的决定。

答案 1 :(得分:4)

在简单的原子价值的情况下,我倾向于不同意这一点的共同智慧,主要是复杂性方面。考虑一个包含帽子的桌子。你可以采用“非规范化”的方式:

CREATE TABLE Hat (
  hat_id INT NOT NULL PRIMARY KEY,
  brand VARCHAR(255) NOT NULL,
  size INT NOT NULL,
  color VARCHAR(30) NOT NULL /* color is a string, like "Red", "Blue" */
)

或者你可以通过制作一个“颜色”表来进一步规范它:

CREATE TABLE Color (
  color_id INT NOT NULL PRIMARY KEY,
  color_name VARCHAR(30) NOT NULL
)

CREATE TABLE Hat (
  hat_id INT NOT NULL PRIMARY KEY,
  brand VARCHAR(255) NOT NULL,
  size INT NOT NULL,
  color_id INT NOT NULL REFERENCES Color(color_id)
)

后者的最终结果是你增加了一些复杂性 - 而不是:

SELECT * FROM Hat

你现在必须说:

SELECT * FROM Hat H INNER JOIN Color C ON H.color_id = C.color_id

这个额外加入是一笔巨额交易吗?不 - 实际上,这是关系设计模型的基础 - 规范化允许您防止数据中可能的不一致。但是像这样的每种情况都会增加一点点的复杂性,除非有充分的理由,否则值得问你为什么这样做。我认为可能有“好理由”包括:

  • 是否有其他属性“悬挂”此属性?您是否正在捕获“颜色名称”和“十六进制值”,以便十六进制值始终取决于颜色名称?如果是这样,那么你肯定想要一个单独的颜色表,以防止一行有(“红色”,“#FF0000”)而另一行有(“红色”,“#FF3333”)的情况。多个相关属性是实体应该规范化的#1信号。
  • 可能的值集会经常更改吗?使用规范化的查找表会使对集合元素的未来更改变得更容易,因为您只是更新了一行。但是,如果不常见,请不要犹豫于必须更新主表中的大量行的语句;数据库非常擅长。如果你不确定的话,做一些速度测试。
  • 用户可以直接管理一组可能的值吗?即。是否有一个屏幕,他们可以添加/删除/重新排序列表中的元素?如果是这样,显然必须使用单独的表格。
  • 不同值的列表是否会为某些UI元素提供动力?例如。 UI中的“颜色”是一个下拉列表?那么你最好在它自己的表中使用它,而不是每次需要显示droplist时在表上执行SELECT DISTINCT。

如果这些都不适用,我很难找到另一个(好的)归一化的理由。如果您只想确保该值是特定(小)合法值集合之一,那么最好使用CONSTRAINT,该值表示该值必须位于特定列表中;保持简单,如果需要,您可以随时“升级”到单独的表格。

答案 2 :(得分:3)

没有人考虑的一件事是,如果其中的数据随时间变化并且加入的记录是历史记录,则不会加入查找表。该示例是零件表和订单表。供应商可能会丢弃零件或更改零件编号,但订单表应该是alawys具有订购时所订购的零件。因此,它应该查找数据以执行记录插入,但是不应该连接到查找表以获取有关现有订单的信息。相反,零件号,描述和价格等应存储在订单表中。这在某种程度上是至关重要的,因此价格变化不会通过历史数据传播并使您的财务记录不准确。在这种情况下,您还希望避免使用任何类型的级联更新。

答案 3 :(得分:2)

rauhr.myopenid.com wrote

  

我们决定解决这个问题的方式是第4种正常形式。   ...

这不是第4范式。这是一个常见的错误,称为One True Lookup: http://www.dbazine.com/ofinterest/oi-articles/celko22

第4种正常形式是: http://en.wikipedia.org/wiki/Fourth_normal_form

答案 4 :(得分:1)

规范化在数据库中被普遍认为是最佳实践的一部分,规范化说是的,你将数据推出并通过密钥引用它。

答案 5 :(得分:1)

您甚至可以规定始终针对视图进行编程,让视图获得查找。

这样可以优化视图并使代码能够抵抗表中的更改。

在oracle中,如果需要,甚至可以将视图转换为物化视图。

答案 6 :(得分:0)

由于没有其他人解决了你的第二点:当查询变得冗长且由于所有这些连接而难以读写时,视图通常会解决这个问题。