之前在设计数据库的时候,有思考过这个问题,到底应该在什么情况下使用外键,什么情况不使用外键?
什么是外键?
一个表中的foreign key指向另一个表中的primary key
用外键的好处:
建键的原则:
用外键的成本你可以参考以下内容:
为何说外键有性能问题?
数据库需要维护外键的内部管理;
外键等于把数据的一致性事务实现,全部交给数据库服务器完成;
有了外键,当做一些涉及外键字段的增,删,更新操作之后,需要触发相关操作去检查,而不得不消耗资源;
外键还会因为需要请求对其他表内部加锁而容易出现死锁情况;
所以,如果项目的服务并发量(增加、删除操作),建议不用外键,大量的这些操作会对数据库服务器有成本消耗。如果查询比较多的,可以使用。
虽然很多人都不推荐你在关系型数据库使用外键。 但你更多听到的是mysql的,而不是SQLserver或者其他。比较公认的是,他的外键设计得的确不是很好,限制多功能不强大等。(同样的,讨论是不是该用存储过程也存在这种思考)
这里贴上一些从博客园看到的,比较严重的问题。
关于对SQL标准的背离(这里只贴其中一个点)
默认的行为应被延迟检查(即约束仅在整个SQL语句被处理之后才被检查)
类似一般的MySQL,在一个插入,删除或更新许多行的SQL语句内,InnoDB逐行检查UNIQUE和FOREIGN KEY约束。
直到InnoDB实现延迟的约束检查之前,一些事情是不可能的,比如删除一个通过外键参考到自身的记录。
外键是个好东西,他为选择了关系型数据库的我们做了约束和级联做了保障。但不使用物理外键的我们也有方案去实现我们的逻辑外键,并保证他正确运行。
数据库上的一个策略:可以选择大多数情况下我们只更新不删除,也就是逻辑删,不再使用的历史数据定期归档来减少压力。
代码上的各种设计和限制:对表范围的操作权限,开启事务去处理逻辑,有需要进行异步操作来提高性能的我们设计补偿机制去弥补,等等。
在我的实际项目中,就靠这一点,直接放弃使用外键。如果表的扩展性需求很高,尽量远离外键。
计划赶不上变化,外键的主从关系是定的,然后你会因为这个做很多事情,但是万一哪天主键所在表就见鬼去了呢?万一哪天你发现外键表不是非得跟人家的主键挂上关系呢?就我经历过的来看,这种情况并不少见,尤其是数据库设计者水平不够高的情况下。
另一个看法比较主观,就是你让数据库去帮你管外键了,你平时写程序的时候就真的很思路清晰吗?因为某些原因(比如你想要的关系数据库不支持,mysql经常),有些地方你就不能设计外键了,到时候一有级联更新的需要时,一部分你靠物理外键,一部分你还得靠自己,我觉得还不如全靠代码逻辑去保证。即使你对业务理解深刻,对外键也掌握的透彻,你也不太希望老是你管一部分他管一部分吧?
最后再来说说一些坚持用外键的思考
有人问:原本在物理外键的开销,在程序上不也有开销吗?的确,但是这样我们对优化性能的方式也灵活了,刚刚说的异步处理就是一种。视具体情况而定,如果设计的好,有时候某些无用数据你不是非得立刻删除他,甚至不是非得删除他。
本文作者:Eric
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!