地址数据库架构 - 更多ForeignKeys还是纯文本?

时间:2015-08-04 09:05:05

标签: django database database-schema

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

说,我有State,City&amp ;;的模型。邮编:

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?也就是说,我应该使用地址模型的第1版,第2版还是第3版:

第一版:

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()

第3版:

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

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

我对不同版本的说明:

第一

  • 创建新记录的开销(最坏的情况:需要创建新的City& Zip;状态已经填充)
  • 更多连接数据(不确定是否是专业人士?)

第二

  • 快速创建新地址记录
  • less" connected"数据(不确定是否是专业人士?)

第三

  • Zip_Code已分配给已分配给州的城市,无需复制此数据

我不确定哪种架构更好,为什么。现在我一直在使用" plain"数据,地址上没有外键,只有CharFields,它可以正常工作。但我的网站正在增长,我希望有一个坚实的基础。另外,我真的很好奇如何解决这个问题。

感谢您抽出宝贵时间阅读本文。

1 个答案:

答案 0 :(得分:1)

从概念上考虑它,这是否适用?

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

这里有一个相当清晰的层次结构。如果您在数据库中反映出来,那么您将拥有以下内容:

  • 持有ZipCode外键的地址。
  • ZipCode持有外键到City。
  • 持有国家外钥的城市。

因此,您对State,City和ZipCode的设计看起来正确;您应该通过选择选项3 来完成它。

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

  • 您将避免更新异常。您不会遇到地址与加利福尼亚州的邮政编码相关/同时持有/与怀俄明州相关的情况。
  • 你不会一遍又一遍地拿着字符串“Illinois” - 除了节省空间,如果你意识到你在三年后不小心输入“Ilinois”,你将不需要进行大量的更新您的实时数据库的地址表上的脚本可以解决问题。
  • 如果州边界发生变化,曾经是亚利桑那州一部分的城市成为新墨西哥州的一部分(好吧,这不太可能,但为了坚持你的榜样而忍受我!),你只会必须更新City表中单个记录的外键。
  • 如果对这些相同的数据有不同的需求(报告?商业智能/分析?一个新的网站功能?),拥有这样一个坚实的结构,每个数据项只保存在一个地方而没有虚假的外键会使它清楚使用哪些数据,将有助于避免耗费时间和可能有问题的数据清理,并缩短开发时间。源系统中重复且不一致的数据占用了我作为商业智能/数据仓库开发人员的大量时间。

您有正确的想法,展望未来,并考虑您当前的数据库设计是否能够经得起您的网站的增长。你越早解决这类问题,他们就越容易改变,你可能遭受的破坏就越少。

如果你目前正在使用类似于Option 2的东西,那么我猜你可能在数据库的其他地方使用了类似的模式。如果是这种情况,并且您想避免我上面提到的问题(以及其他问题),那么确实值得对数据库设计进行一些阅读或培训,特别是如何进行规范化。