我发现这很多,我不确定接近它的最佳方法.
我的问题是如何在使用外键查找表或直接在请求它的表中使用查找表值之间做出决定,完全避免查找表关系.
要记住的要点:
使用第二种方法,如果在查找表中更改了数据,则需要对引用数据的所有记录进行批量更新.
这更侧重于有很多列引用许多查找表的表.因此,每次查询表时,许多外键意味着很多连接.
此数据将来自下拉列表,这些列表将从查找表中提取.为了在重新加载时匹配数据,值必须在现有列表中(与第一个点相关).
这里有最佳实践,还是需要考虑的关键点?
您可以将查找表与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
那额外的加入是一笔大买卖吗?否-实际上,这是关系设计模型的基础-规范化允许您防止数据中可能出现的不一致。但是,每一种这样的情况都会增加一点点复杂性,除非有充分的理由,否则值得问一问为什么这么做。我认为可能的“充分理由”包括:
是否还有其他属性与该属性“脱离”?您是否同时捕获“颜色名称”和“十六进制值”,以使十六进制值始终取决于颜色名称?如果是这样,那么您绝对需要一个单独的颜色表,以防止出现一行(“红色”,“#FF0000”)和另一行(“红色”,“#FF3333”)的情况。多个相关属性是实体应归一化的#1信号。
可能值的集合会经常变化吗?使用规范化的查找表将使将来对集合元素的更改更加容易,因为您仅更新了一行。但是,如果这种情况很少见,请不要对必须更新主表中许多行的语句感到厌烦;数据库非常擅长于此。如果不确定,请进行一些速度测试。
一组可能的值将由用户直接管理吗?即有没有一个屏幕,他们可以在其中添加/删除/重新排序列表中的元素?如果是这样,显然必须有一个单独的表。
独特值列表会为某些UI元素提供动力吗?例如,“颜色”是用户界面中的下拉列表吗?然后,最好将其放在自己的表中,而不是每次需要显示下拉列表时都在表上执行SELECT DISTINCT。
如果这些都不适用,我将很难找到另一个(好的)归一化的理由。如果您只是想确保该值是某个(较小)合法值集中的一个,则最好使用CONSTRAINT,该值表示该值必须在特定列表中。使事情保持简单,如果需要,您以后随时可以“升级”到单独的表。