数据库:不可变数据的外键或非规范化表?

时间:2011-03-10 03:21:17

标签: database-design

假设:

Person[id, name, city, state, country]

我最好直接在主表中存储城市名称而不是将外键存储到单独的cities表中?出于本讨论的目的,假设城市名称是不可变的。这就是我的想法:

选项1 :将值存储为内联。

Person[id, name, city, state, country]
  • Pro:轻松插入。快速查询。
  • 缺点:增加磁盘空间/内存使用量
  • 非常适合小值,不经常重复。

选项2 :指向单独表格的外键

Person[id, name, city_id, state_id, country_id]
Cities[id, name]
States[id, name]
Countries[id, name]
  • Pro:减少磁盘空间/内存使用量。可能更容易缓存常用值。
  • 缺点:插入更复杂(城市已经存在或是否应该插入?)
  • 非常适合大值,频繁重复。

引用http://en.wikipedia.org/wiki/Database_normalization:“目标是隔离数据,以便可以在一个表中添加,删除和修改字段,然后通过定义的关系在数据库的其余部分传播。 “在我看来,这些好处在处理不可变数据时会飞出窗口,因为它永远不需要更新。至于插入和删除异常,我们可以使用可空列(如果需要)。

此案例的最佳做法是什么?

3 个答案:

答案 0 :(得分:1)

Option 2: Foreign keys to a separate table

Person[id, name, city_id, state_id, country_id]
Cities[id, name]
States[id, name]
Countries[id, name]

“规范化”并不意味着“用id号替换名称”。你应该追捕那些教你的人,并用手指将它们戳在眼睛里。 (或者更好的是,两只眼睛。两根手指。)

“规范化”涉及识别列之间的关联(“功能依赖性”),并将它们隔离在不同的表中(“投影”)。规范化通过减少或消除某些类型的INSERT,UPDATE和DELETE异常来提高数据完整性。

稍后。 。

人员表的一些示例数据。 。

id  name          city   state           country
--
1   John Smith    York   Alabama         United States of America
2   John Doe      York   Maine           United States of America
3   Jane Smith    York   Nebraska        United States of America
4   Jane Doe      York   South Carolina  United States of America

你是对的,原始表是2NF。它不在3NF,因为“国家”是关于{city,state}的事实。所以你可以用这两个表替换原来的人员表。

people
id  name          city   state           
--
1   John Smith    York   Alabama         
2   John Doe      York   Maine           
3   Jane Smith    York   Nebraska        
4   Jane Doe      York   South Carolina  

cities -- key is (city, state)
city   state           country  
--
York   Alabama         United States of America
York   Maine           United States of America
York   Nebraska        United States of America
York   South Carolina  United States of America

需要注意的两件事:1)分解从原始表中删除了一列。 2)分解不涉及添加任意id号。

现在这些表格的正常形式是什么?


您可以使用国家/地区代码替换国家/地区名称,从而减少所需的存储空间您可以首先将ISO国家/地区代码与“城市”表中的其他属性一起存储。

cities -- key is (city, state)
city   state           country                    iso_cc
--
York   Alabama         United States of America    US
York   Maine           United States of America    US
York   Nebraska        United States of America    US
York   South Carolina  United States of America    US

但是通过添加一列,我们将功能依赖的数量从一个增加到四个。

{city, state} -> country
{city, state} -> iso_cc
country -> iso_cc
iso_cc -> country

我们可以通过创建国家/地区表来删除这两个传递依赖项。删除列“country”是有意义的,并保留列“iso_cc”有两个原因。 “iso_cc”列更短,人类可以读取它。由于人类可以阅读它,我们通常不必加入表“国家”。

cities -- key is (city, state)
city   state           iso_cc
--
York   Alabama         US
York   Maine           US
York   Nebraska        US
York   South Carolina  US

countries -- keys are iso_cc and country
iso_cc   country
--
US       United States of America

请注意,表“countries”有两个候选键。每列都是唯一的。根据我的经验,大多数数据库都不会强制执行这些约束。简单地用id号替换名称的开发人员经常错过第二个。 (那个“国家”是唯一的,不仅是身份证号码。)

答案 1 :(得分:0)

除了您的要点之外,规范化数据库还将标准化城市的命名。但是,您需要使用世界上所有城市填充您的城市表。否则,你最终会得到像纽约和纽约这样的东西。

除非您计划提供超出名称的城市信息(例如大小,地理坐标等),否则我会坚持使用字符串城市名称。如果您的代码是好的,那么无论何时需要,您都可以正常化。

答案 2 :(得分:0)

你当然可以有一个国家表,PK = ISO代码。只需搜索网络,您就会找到一份现成的清单。除非您的行号非常高(> 10 ^ 6),否则您不会关心地址的其余部分,或者您计划使用Dimitry指向的专用用途。
如果您决定采用这种方式,最终可能会得到一个位置表,其中PK =(CountryISO,PostalCode)和额外字段= City。 但是你要节省多少钱?