本来我一个小菜鸟,没有什么项目开发经验,关心这个问题也属于纸上谈兵。但自从知道有不用外键,全由程序控制数据完整性的 方法后,我在学校接受的“外键是必须的“思想就承受了一定程度的颠覆。最近又遇上类似的问题,就在网上搜罗了一下,结果百家争鸣,众说纷纭,跟华山论剑似 的,看得一头浆糊。想想算了,以后的工作中再加深体验,权且记下各方观点好了:
正方(这个必须有):
1,由数据库自身保证数据一致性,完整性,更可靠,因为程序很难100%保证数据 的完整性,而用外键即使在数据库服务器当机或者出现其他问题的时候,也能够最大限度的保证数据的一致性和完整性。
eg:数据库和应用是一对多的关系,A应用会维护他那部分数据的完整性,系统一变大时,增加了B应用,A和B两个应用也许是不同的开发团队来做的。他们如何协调保证数据的完整性,而且一年以后如果又增加了C应用呢?
2,有主外键的数据库设计可以增加ER图的可读性,这点在数据库设计时非常重要。
3,外键在一定程度上说明的业务逻辑,会使设计周到具体全面
4,除非能证明触发器的性能和可维护性比外键更优,否则凭什么一定要否定外键呢?使用应用程序来维护数据完整性,则是严重降低数据库安全性的一种做法。连接字符串里如果有uid和pwd或者类似的这两个东西,可以使用工具获取你数据库的帐号。因为每次建立数据库联接的时候都会在网线上以标准格式传递这些信息。从此编码内的任何保证都是空的。
5,不使用外键,会导致数据冗余,在级联最底层的表可能会重复好几层的数据
必然导致最底层的表数据量翻倍,IO瓶颈是数据库性能瓶颈之一
反方(这个可以没有):
1,可以用触发器或应用程序保证数据的完整性
2,过分强调或者说使用主键/外键会平添开发难度,导致表过多等问题
3,不用外键时数据管理简单,操作方便,性能高(导入导出等操作,在insert, update, delete 数据的时候更快)
eg: 在海量的数据库中想都不要去想外键,试想,一个程序每天要insert数百万条记录,当存在外键约束的时候,每次要去扫描此记录是否合格,一般还不止一个 字段有外键,这样扫描的数量是成级数的增长!我的一个程序入库在3个小时做完,如果加上外键,需要28个小时!
4,几乎不用,抛开性能不说,开发、测试、部署、实施,以及维护的时候都带来不少问题。数据完整性几乎都是业务的要求,理应由业务部分负责维护,而不是依赖数据库访问量较大的web应用,以及有一定规模的企业应用,都关注伸缩性和性能问题,各种形式的垂直、水平切分运用越来越多,外键、触发器、存储过程之类的基本属禁区
平衡点?
1.设计文档及设计数据库之初使添加合理的外键约整。并做为维护及参考依据。因为真正的数据维护不是去看数据库,而是看文档,文档是同步到当前的平台的就可以了,至于当前运行的数据库是否存在这些约束,并不是那么重要。
2. 导出开发版数据库及测试或标准数据库,开发版数据库不带外键约束;这样的好处是模块开发人员之间不用创建完整的数据链就可以测试自己的业务逻辑,因为开发 过程中其它编码人员可能都还没有写好相应的操作类,你没法去操作其它编码人员的关联表。这个时候还是不带外键来得方便。
3.模块开发完成后,编码人员对代码进行整合测试时发布到测试环境时使用带有外键的标准约束数据库进行测试,如果违反了外键约束,自然程序会运行不下去了,这样可以暴露出大部分数据逻辑上的缺陷。
4.测试完成后发布正确的版本,并发布数据库,该数据库与开发环境数据库一样,删除掉外键约束。这样我个人觉得比较合适。
这样数据库使用不同的版本的好处是:
1:利于前期开发,保证严格的测试环境,保留约束关系可以用以检验编码人员的数据逻辑是否正确,测试完成后发布版本即可以不需要约束的限制(前提:测试的时候有认真的去测试了。)
2:方便代码生成工具生成关键表操作代码,以及部分orm系统能很好的利用关联关系。
反驳:
这样的说法我觉得是行不通的,实际上绝大多数的软件系统根本不是“开发”-》“发布”两个过程就简单完事了的;而是要经历很长的维护和反复开发测试等阶段。所以外键应该是贯穿始终都要有的。
正方(这个必须有):
1,由数据库自身保证数据一致性,完整性,更可靠,因为程序很难100%保证数据 的完整性,而用外键即使在数据库服务器当机或者出现其他问题的时候,也能够最大限度的保证数据的一致性和完整性。
eg:数据库和应用是一对多的关系,A应用会维护他那部分数据的完整性,系统一变大时,增加了B应用,A和B两个应用也许是不同的开发团队来做的。他们如何协调保证数据的完整性,而且一年以后如果又增加了C应用呢?
2,有主外键的数据库设计可以增加ER图的可读性,这点在数据库设计时非常重要。
3,外键在一定程度上说明的业务逻辑,会使设计周到具体全面
4,除非能证明触发器的性能和可维护性比外键更优,否则凭什么一定要否定外键呢?使用应用程序来维护数据完整性,则是严重降低数据库安全性的一种做法。连接字符串里如果有uid和pwd或者类似的这两个东西,可以使用工具获取你数据库的帐号。因为每次建立数据库联接的时候都会在网线上以标准格式传递这些信息。从此编码内的任何保证都是空的。
5,不使用外键,会导致数据冗余,在级联最底层的表可能会重复好几层的数据
必然导致最底层的表数据量翻倍,IO瓶颈是数据库性能瓶颈之一
反方(这个可以没有):
1,可以用触发器或应用程序保证数据的完整性
2,过分强调或者说使用主键/外键会平添开发难度,导致表过多等问题
3,不用外键时数据管理简单,操作方便,性能高(导入导出等操作,在insert, update, delete 数据的时候更快)
eg: 在海量的数据库中想都不要去想外键,试想,一个程序每天要insert数百万条记录,当存在外键约束的时候,每次要去扫描此记录是否合格,一般还不止一个 字段有外键,这样扫描的数量是成级数的增长!我的一个程序入库在3个小时做完,如果加上外键,需要28个小时!
4,几乎不用,抛开性能不说,开发、测试、部署、实施,以及维护的时候都带来不少问题。数据完整性几乎都是业务的要求,理应由业务部分负责维护,而不是依赖数据库访问量较大的web应用,以及有一定规模的企业应用,都关注伸缩性和性能问题,各种形式的垂直、水平切分运用越来越多,外键、触发器、存储过程之类的基本属禁区
平衡点?
1.设计文档及设计数据库之初使添加合理的外键约整。并做为维护及参考依据。因为真正的数据维护不是去看数据库,而是看文档,文档是同步到当前的平台的就可以了,至于当前运行的数据库是否存在这些约束,并不是那么重要。
2. 导出开发版数据库及测试或标准数据库,开发版数据库不带外键约束;这样的好处是模块开发人员之间不用创建完整的数据链就可以测试自己的业务逻辑,因为开发 过程中其它编码人员可能都还没有写好相应的操作类,你没法去操作其它编码人员的关联表。这个时候还是不带外键来得方便。
3.模块开发完成后,编码人员对代码进行整合测试时发布到测试环境时使用带有外键的标准约束数据库进行测试,如果违反了外键约束,自然程序会运行不下去了,这样可以暴露出大部分数据逻辑上的缺陷。
4.测试完成后发布正确的版本,并发布数据库,该数据库与开发环境数据库一样,删除掉外键约束。这样我个人觉得比较合适。
这样数据库使用不同的版本的好处是:
1:利于前期开发,保证严格的测试环境,保留约束关系可以用以检验编码人员的数据逻辑是否正确,测试完成后发布版本即可以不需要约束的限制(前提:测试的时候有认真的去测试了。)
2:方便代码生成工具生成关键表操作代码,以及部分orm系统能很好的利用关联关系。
反驳:
这样的说法我觉得是行不通的,实际上绝大多数的软件系统根本不是“开发”-》“发布”两个过程就简单完事了的;而是要经历很长的维护和反复开发测试等阶段。所以外键应该是贯穿始终都要有的。
另外一个情况:当用sql语言备份数据库时,到时导入备份插入数据时,若外键表的sql数据在后,
此时插入的时候就会报错;
此时插入的时候就会报错;