Django 地址数据库模式-更多外键还是纯文本?
我在为我的应用程序设计数据库时左右为难。基本上,我想要存储地址。我使用的是Django,但更多的是数据库设计问题 比如说,我有州、市和ZipCode的模型:Django 地址数据库模式-更多外键还是纯文本?,django,database,database-schema,Django,Database,Database Schema,我在为我的应用程序设计数据库时左右为难。基本上,我想要存储地址。我使用的是Django,但更多的是数据库设计问题 比如说,我有州、市和ZipCode的模型: class State(models.Model): short_name = models.CharField(_('state short name'), max_length=2, primary_key=True) name = models.CharField(_('state full name'), max_l
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个版本:
第1版:
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()
第三版:
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%的冗余搜索
我对不同版本的注释:
第一:
- 创建新记录的开销(最坏情况:需要创建新的城市&Zip;州已填充)
- 更多连接的数据(不确定这是赞成还是反对?)
- 快速创建新地址记录
- 较少的“连接”数据(不确定这是赞成还是反对?)
- 邮政编码已分配给城市,城市已分配给州,无需复制此数据
感谢您花时间阅读此文。从概念上思考,这是否成立
- 一个州有一个或多个城市
- 一个城市有一个或多个邮政编码
- 邮政编码有一个或多个街道地址
- 持有ZipCode外键的地址
- ZipCode持有城市的外键
- 持有国家外键的城市
- 您将避免更新异常。你永远不会遇到这样的情况:一个地址与来自加利福尼亚州的邮政编码相关,同时又与怀俄明州相关
- 您将不会一次又一次地保留字符串“Illinois”-除了节省空间之外,如果您在三年后意识到您意外地键入了“Ilinois”,您将不需要在live数据库的地址表上执行大量更新脚本来纠正此问题
- 如果一个州的边界发生了变化,一个曾经是亚利桑那州一部分的城市变成了新墨西哥州的一部分(好吧,这不太可能,但是为了坚持你的例子,请耐心听我说!),你只需要在city表中的一条记录上更新外键
- 如果对相同的数据有不同的需求(报告?商业智能/分析?新的网站功能?),有这样一个坚实的结构,每个数据项只保存在一个地方,没有伪造的外键,这将清楚地表明要使用哪些数据,将有助于避免耗时和潜在问题的数据清理,并将减少开发时间。源系统中重复且不一致的数据占用了我作为商业智能/数据仓库开发人员的大量时间
展望未来,思考当前的数据库设计是否能够经得起网站的发展,您的想法是正确的。你越早解决这样的问题,它们就越容易改变,你可能遭受的干扰也就越少
如果您当前使用的是类似于选项2的东西,那么我猜您很可能在数据库的其他地方使用了类似的模式。如果是这种情况,并且您希望避免我上面提到的问题(以及其他问题),那么在数据库设计方面,特别是如何执行规范化方面,确实值得进行一些阅读或培训。我感谢您全面的回答和解释,谢谢。我了解数据库设计和规范化的基础知识,我知道一致性数据库比不一致性数据库好。在这种特殊情况下,我主要关心的是性能/速度,因为地址搜索是最频繁的操作,我需要尽快返回结果(地址“upsert”只是过程的一部分)。您关于报告/BI的观点对我最有帮助,并说服我使用第三版。谢谢大家!@iyn很高兴它有所帮助,也很高兴在数据质量的斗争中赢得了一些人的支持!;)在保持数据完整性的同时进行优化时,最安全的计划是首先建立一个规范化的结构。然后确保有合适的索引,并在必要/可能的地方调整查询。有时,非规范化(或使用非关系数据库)是正确的答案,但与所有优化一样,避免过早地进行。