地址数据库模式 - 更多外键或纯文本?

Address DB schema - more ForeignKeys or just plain text?

我在为我的应用程序设计数据库时遇到了难题。基本上,我想存储美国地址。我正在使用 Django,但它更像是一个数据库设计问题。

说,我有州、城市和邮政编码的模型:

class State(models.Model):
    short_name = models.CharField(_('state short name'), max_length=2, primary_key=True)
    name = models.CharField(_('state full name'), max_length=50)

class City(models.Model):
    name = models.CharField(_('city name'), max_length=100)
    state = models.ForeignKey(State)

class ZipCode(models.Model):
    code = models.CharField(_('zip code'), max_length=6)
    city = models.ForeignKey(City)

然后,我想存储一个地址。这是我的困境:我应该使用外键(或只使用一个外键)还是将整个地址存储为 CharFields?也就是说,我应该使用第一个、第二个还是第三个版本的地址模型:

第一个版本:

class Address(models.Model):
    street = models.CharField(_('street address'), max_length=300)
    city = models.ForeignKey(City)
    zip_code = models.ForeignKey(ZipCode)
    state = models.ForeignKey(State)
    counter = models.IntegerField()

第二版:

class Address(models.Model):
    street = models.CharField(_('street address'), max_length=300)
    city = models.CharField(_('city'), max_length=300)
    zip_code = models.CharField(_('zip code'), max_length=6)
    state = models.CharField(_('state'), max_length=50)
    counter = models.IntegerField()

第三版:

class Address(models.Model):
    street = models.CharField(_('street address'), max_length=300)
    zip_code = models.ForeignKey(ZipCode)
    counter = models.IntegerField()

我的具体用例是每次用户搜索都会生成计数器 = 0 的新地址(如果不存在)或更新现有地址(例如,增加计数器字段;这只是一个示例)。假设每秒进行 1 次搜索,其中 ~30% 是冗余搜索。

我的不同版本笔记:

第一名:

第二名:

第三名:

我只是不确定哪个模式更好以及为什么。现在我一直在使用 "plain" 数据,地址上没有外键,只有 CharFields,它工作正常。但是我的网站正在发展,我想有一个坚实的基础。另外,我真的很好奇如何解决这样的问题。

感谢您花时间阅读本文。

从概念上思考一下,这是否成立?

  • 一个州有一个或多个城市。
  • 一个城市有一个或多个邮政编码。
  • 一个邮政编码有一个或多个街道地址。

这里有一个相当清晰的层次结构。如果将其反映在数据库中,则将具有以下内容:

  • 持有 ZipCode 外键的地址。
  • 拥有城市外键的邮政编码。
  • 持有州外键的城市。

所以您对州、城市和邮政编码的设计看起来是正确的;您应该通过选择 选项 3.

来完成它

以下是此设计的一些好处:

  • 您将避免更新异常。您永远不会遇到这样的情况:地址 holds/is 与加利福尼亚的邮政编码相关,同时 holding/being 与怀俄明州相关。
  • 你不会一遍又一遍地持有字符串 "Illinois" - 除了保存 space,如果你意识到你在三年后不小心输入了 "Ilinois",你不需要在您的实时数据库的地址 table 上执行大量更新脚本来纠正问题。
  • 如果州界发生变化,并且曾经属于亚利桑那州的城市成为新墨西哥州的一部分(好吧,这不太可能,但为了坚持你的例子,请耐心等待!),你d 只需更新城市 table.
  • 中单条记录的外键
  • 如果对相同的数据有不同的需求(报告?业务 intelligence/analytics?新的网站功能?),具有像这样的可靠结构,每个数据项只保存在一个地方并且没有虚假外键将明确使用哪些数据,将有助于避免耗时且可能有问题的数据清理,并将减少开发时间。源系统中重复和不一致的数据占用了我作为业务 intelligence/data 仓储开发人员的大量时间。

您在展望未来并思考您当前的数据库设计是否能经得起您网站的发展方面的想法是正确的。您越早解决此类问题,它们就越容易改变,您遭受的干扰也就越少。

如果您目前正在使用更像选项 2 的东西,那么我猜您很可能在数据库的其他地方使用了类似的模式。如果是这种情况,并且您想避免我上面提到的问题(以及其他问题),那么真的值得阅读或培训有关数据库设计的内容,特别是如何进行规范化。