纠结的外键
时间:2014-12-08 14:24 来源:linux.it.net.cn 作者:IT
外键是我们经常使用的手段,用于维护父子表之间的完整性关系。但是实际中,我们选择作出外键的抉择有时是比较纠结的。
数据库的一个重要功能就是维护数据的完整性。关系数据库使用数据表作为数据存储的基本结构,通过表之间的连接构造复杂的实体关系模型结构。
在维护数据完整性方面,一般商用DBMS都可以提供较好的支持方案,如主键、外键、约束、触发器等,都可以从各个层面上保证数据库数据对业务规则的满足。其中,外键是我们比较常见的手段。
简而言之,外键的作用就是在数据库层面上链接两个表,建立父子表关系。在子表中,引用了父表的某列数值(通常为主键)。当进行指定的DML操作后,子表外键列出现了父表引用列中没有出现过的值,违背外键原则,数据库层面拒绝操作。
外键不是唯一的手段,我们是可以在应用程序层面实现完整性。在进行一个业务操作之前,可以由应用程序(包括App Server)对数据库进行检索完整性、级联删除操作,之后给出一个用户易于接受的提示内容。
那么,面对两层的完整性维护选择,我们如何抉择?应用程序检查和外键如何选取?
对数据库外键,一般都要求我们将所有的外键关系建立完整。构建一个在数据库层面的安全网。很多技术专家对于外键给出了相同的答案:尽可能的在数据库层面上建立完整性维护网络,应用程序层面的验证是不可相信的。
事实可能也的确有道理。在一些没有进行完整性控制的数据库设计结构中,非常容易出现完整性破坏数据。这其中的原因是多方面的。
首先,我们有很多手段可以访问到数据库中的数据,而绝非应用程序一种途径。直接的数据库的访问,可以轻易的善意或恶意的破坏数据完整性,造成数据损害。没有数据库层面完整性约束的条件下,这种发生机率是很高的。
其次,进行完整性控制是对业务和技术要求很高的任务。业务上,这样的风险出现更多一些。开发人员可能因为对业务的生疏、或者干脆忘记关联完整性问题,在应用代码中没有进行完整性控制和维护。技术上,进行完整性验证,特别是多次与数据库交互的情况下,是需要对锁和并发机制有较高层次,毕竟不能保证每个开发人员都能达到这种标准。
最后,费劲心力完成的应用程序完整性约束也存在性能和结构性问题。大部分DBMS的完整性约束代码都是高效的,性能上较我们应用端开发代码好得多。而且,分布在代码各处的验证逻辑也是为日后运维和重构带来比较大的工作量。
讨论到这里。似乎真相只有一个:尽可能加入外键,保证数据库端完整性。
但是,世上没有免费的午餐。外键也要有所付出。
外键代表了表之间的连接,代表查询可能出现连接、DML操作要进行内部的检查。通常要对子表上的外键列加索引,用来加快查询链接效率和防止DML引发的挂起。
如果我们的业务核心表信息中包括了很多基础信息,如类型、编码等字段。每个字段都是分析出一个对应的参考信息表。这样,参考信息表就成为主表,而核心业务表就成为多张参考信息表的子表。
在这种情况下,如果我们遵守上面说的外键原则,就要设置主外键关系,并且在子表外键列上加入索引。核心业务表为了外键的关系就加入了很多的索引内容。
对于索引,我们首先承认是一种加快信息检索效率的工具,但是也要意识到索引的成本因素(可参见http://space.itpub.net/17203031/viewspace-681121 )。索引带来的最直接影响就是DML操作的性能问题。对核心业务表而言,这种性能的损耗有的时候还是不容易接受的。
如何平衡这两各方面呢?下面阐述笔者的一点拙见:
首先,在应用程序层面,要进行完整的完整性验证,向终端用户提供良好的客户体验。通过代码走查和持续的代码重构,最大程度的降低应用层面数据完整性代码功能的缺陷。
其次,对核心业务表之间,要使用外键进行关联。核心业务表是系统中最重要的部分,进行数据库层别的完整性保护是有必要的。同时,虽然核心业务表与参考信息表之间通常是不对称式的子父表关系(核心业务表是一个多父表的子表),但是核心业务表之间的主外键关系还是比较均匀的。在其之间建立外键关联,并且在子表外键列加索引是可以接受的。
此外,参考信息适度冗余在子表上。对于核心业务表上的参考信息信息,可以加入参考信息主键和一些重要信息(如:业务编码、编号等,这些信息不容易被修改)。通过这样的适度冗余,可以减少表间连接的发生,也不需要强制性的外键建立。(但要保证应用层面的操作验证)
最后,如果参考信息中,需要与核心业务表连接的内容比较多,使用冗余手段不恰当时,再考虑建立外键关联关系。当参考信息中,很多内容都需要与核心业务表相关联出现(如出报表),同时这些参考信息修改的情况较多(冗余信息连带修改量大),就需要建立外键关联,维护业务表上的外键列索引。
总而言之,选取基于的原则就是业务需要和成本比算。如果一个参考信息,冗余内容永远不会改变,业务上永远不会使用其与核心业务表进行连接。那么加入强制外键和索引的意义也就不大。如果这种连接情况很多,操作很频繁,加入外键和索引后获得的性能收益能够超过维护外键和索引的成本,那么选择加外键就是一个明智的选择。
实际中,开发阶段可以选择先加入所有外键和索引,在应用程序没有成熟的情况下保护数据库完整性。当系统测试通过、投产之后,性能出现了瓶颈,可以考虑剔除一部分的外键和与之的索引信息。这样既保证了系统功能完善阶段,又能适度的减少外键索引的负担。
(责任编辑:IT)
外键是我们经常使用的手段,用于维护父子表之间的完整性关系。但是实际中,我们选择作出外键的抉择有时是比较纠结的。 数据库的一个重要功能就是维护数据的完整性。关系数据库使用数据表作为数据存储的基本结构,通过表之间的连接构造复杂的实体关系模型结构。 在维护数据完整性方面,一般商用DBMS都可以提供较好的支持方案,如主键、外键、约束、触发器等,都可以从各个层面上保证数据库数据对业务规则的满足。其中,外键是我们比较常见的手段。 简而言之,外键的作用就是在数据库层面上链接两个表,建立父子表关系。在子表中,引用了父表的某列数值(通常为主键)。当进行指定的DML操作后,子表外键列出现了父表引用列中没有出现过的值,违背外键原则,数据库层面拒绝操作。 外键不是唯一的手段,我们是可以在应用程序层面实现完整性。在进行一个业务操作之前,可以由应用程序(包括App Server)对数据库进行检索完整性、级联删除操作,之后给出一个用户易于接受的提示内容。 那么,面对两层的完整性维护选择,我们如何抉择?应用程序检查和外键如何选取? 对数据库外键,一般都要求我们将所有的外键关系建立完整。构建一个在数据库层面的安全网。很多技术专家对于外键给出了相同的答案:尽可能的在数据库层面上建立完整性维护网络,应用程序层面的验证是不可相信的。 事实可能也的确有道理。在一些没有进行完整性控制的数据库设计结构中,非常容易出现完整性破坏数据。这其中的原因是多方面的。 首先,我们有很多手段可以访问到数据库中的数据,而绝非应用程序一种途径。直接的数据库的访问,可以轻易的善意或恶意的破坏数据完整性,造成数据损害。没有数据库层面完整性约束的条件下,这种发生机率是很高的。 其次,进行完整性控制是对业务和技术要求很高的任务。业务上,这样的风险出现更多一些。开发人员可能因为对业务的生疏、或者干脆忘记关联完整性问题,在应用代码中没有进行完整性控制和维护。技术上,进行完整性验证,特别是多次与数据库交互的情况下,是需要对锁和并发机制有较高层次,毕竟不能保证每个开发人员都能达到这种标准。 最后,费劲心力完成的应用程序完整性约束也存在性能和结构性问题。大部分DBMS的完整性约束代码都是高效的,性能上较我们应用端开发代码好得多。而且,分布在代码各处的验证逻辑也是为日后运维和重构带来比较大的工作量。 讨论到这里。似乎真相只有一个:尽可能加入外键,保证数据库端完整性。 但是,世上没有免费的午餐。外键也要有所付出。 外键代表了表之间的连接,代表查询可能出现连接、DML操作要进行内部的检查。通常要对子表上的外键列加索引,用来加快查询链接效率和防止DML引发的挂起。 如果我们的业务核心表信息中包括了很多基础信息,如类型、编码等字段。每个字段都是分析出一个对应的参考信息表。这样,参考信息表就成为主表,而核心业务表就成为多张参考信息表的子表。 在这种情况下,如果我们遵守上面说的外键原则,就要设置主外键关系,并且在子表外键列上加入索引。核心业务表为了外键的关系就加入了很多的索引内容。 对于索引,我们首先承认是一种加快信息检索效率的工具,但是也要意识到索引的成本因素(可参见http://space.itpub.net/17203031/viewspace-681121 )。索引带来的最直接影响就是DML操作的性能问题。对核心业务表而言,这种性能的损耗有的时候还是不容易接受的。 如何平衡这两各方面呢?下面阐述笔者的一点拙见: 首先,在应用程序层面,要进行完整的完整性验证,向终端用户提供良好的客户体验。通过代码走查和持续的代码重构,最大程度的降低应用层面数据完整性代码功能的缺陷。 其次,对核心业务表之间,要使用外键进行关联。核心业务表是系统中最重要的部分,进行数据库层别的完整性保护是有必要的。同时,虽然核心业务表与参考信息表之间通常是不对称式的子父表关系(核心业务表是一个多父表的子表),但是核心业务表之间的主外键关系还是比较均匀的。在其之间建立外键关联,并且在子表外键列加索引是可以接受的。 此外,参考信息适度冗余在子表上。对于核心业务表上的参考信息信息,可以加入参考信息主键和一些重要信息(如:业务编码、编号等,这些信息不容易被修改)。通过这样的适度冗余,可以减少表间连接的发生,也不需要强制性的外键建立。(但要保证应用层面的操作验证) 最后,如果参考信息中,需要与核心业务表连接的内容比较多,使用冗余手段不恰当时,再考虑建立外键关联关系。当参考信息中,很多内容都需要与核心业务表相关联出现(如出报表),同时这些参考信息修改的情况较多(冗余信息连带修改量大),就需要建立外键关联,维护业务表上的外键列索引。 总而言之,选取基于的原则就是业务需要和成本比算。如果一个参考信息,冗余内容永远不会改变,业务上永远不会使用其与核心业务表进行连接。那么加入强制外键和索引的意义也就不大。如果这种连接情况很多,操作很频繁,加入外键和索引后获得的性能收益能够超过维护外键和索引的成本,那么选择加外键就是一个明智的选择。 实际中,开发阶段可以选择先加入所有外键和索引,在应用程序没有成熟的情况下保护数据库完整性。当系统测试通过、投产之后,性能出现了瓶颈,可以考虑剔除一部分的外键和与之的索引信息。这样既保证了系统功能完善阶段,又能适度的减少外键索引的负担。 (责任编辑:IT) |