我发现这个问题很多,我不确定最好的方法。
我的问题是如何在使用外键查找表或直接在请求它的表中使用查找表值之间做出决定,完全避免查找表关系。
要记住的几点:
使用第二种方法,如果在查找表中更改了数据,您将需要对引用数据的所有记录进行大规模更新。
这更侧重于具有大量列引用许多查找表的表。因此,每次查询表时,大量外键意味着大量连接。
- 该数据将来自从查找表中提取的下拉列表。为了在重新加载时匹配数据,值需要在现有列表中(与第一点相关)。
这里有最佳实践,还是需要考虑的关键点?
我发现这个问题很多,我不确定最好的方法。
我的问题是如何在使用外键查找表或直接在请求它的表中使用查找表值之间做出决定,完全避免查找表关系。
要记住的几点:
使用第二种方法,如果在查找表中更改了数据,您将需要对引用数据的所有记录进行大规模更新。
这更侧重于具有大量列引用许多查找表的表。因此,每次查询表时,大量外键意味着大量连接。
这里有最佳实践,还是需要考虑的关键点?
您可以使用带有 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 行表中的主键大小无关紧要。但是该查找表可能会被其他表中的数百万或数十亿行引用!
没有适用于所有情况的正确答案。对于不同的情况,任何答案都可能是正确的。您只需了解权衡取舍,并尝试根据具体情况做出明智的决定。
在简单的原子值的情况下,我倾向于不同意这一点的普遍智慧,主要是在复杂性方面。考虑一张包含帽子的桌子。您可以执行“非规范化”方式:
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
额外的加入是一笔大买卖吗?不——事实上,这是关系设计模型的基础——规范化可以防止数据中可能出现的不一致。但是像这样的每一种情况都会增加一点复杂性,除非有充分的理由,否则值得问问你为什么要这样做。我认为可能的“充分理由”包括:
如果这些都不适用,我很难找到另一个(好的)理由来规范化。如果您只是想确保该值是某个(小)合法值集之一,则最好使用 CONSTRAINT 表示该值必须在特定列表中;让事情变得简单,如果需要,您可以随时“升级”到单独的表。
没有人考虑过的一件事是,如果查找表中的数据可以随时间变化并且加入的记录是历史记录,则您不会加入查找表。示例是零件表和订单表。供应商可能会丢弃零件或更改零件编号,但订单表应始终准确包含订购时订购的内容。因此,它应该查找数据以进行记录插入,但绝不应该加入查找表以获取有关现有订单的信息。相反,零件编号、描述和价格等应存储在订单表中。这一点尤其重要,这样价格变化就不会通过历史数据传播,并使您的财务记录不准确。在这种情况下,您还希望避免使用任何类型的级联更新。
rauhr.myopenid.com写道:
我们决定解决这个问题的方法是使用第四范式。...
这不是第四范式。这是一个常见的错误,称为 One True Lookup: http ://www.dbazine.com/ofinterest/oi-articles/celko22
规范化被普遍认为是数据库最佳实践的一部分,规范化说是的,你将数据推出并通过键引用它。
由于没有其他人解决您的第二点:当查询由于所有这些连接而变得冗长且难以读写时,视图通常会解决该问题。
您甚至可以制定一条规则,始终针对视图进行编程,让视图获取查找。
这使得优化视图和使您的代码能够抵抗表中的更改成为可能。
在 oracle 中,如果需要,您甚至可以将视图转换为物化视图。