转自 :http://hi.baidu.com/zbzb/blog/item/f2e61a95d78ba90a7af480b0.html
2007年08月06日 星期一 上午 09:54
业务主键和代理主键的比较
这是个老话题,人们在做数据库设计时常常按照个人偏好或一些技术文档上的简单推荐来选择它们二者,但是世上没有放之四海而皆准的东西,所以它们两者一定会相对更适合应用于不同的环境。下面对两者各种的优势加以说明。
优势和不足
下文中提到的“业务编号”是可以唯一确定一条记录的有意义的内容,也就是业务主键。
业务主键优势
业务主键
代理主键
1
具有更好的检索性能。同时基于主键检索更加方便。
因为使用业务主键来查询关联表时,可以减少连接主表的几率,减小I/O量。
连接开销只能通过增加冗余来解决,即在子表中保存主表的“业务编号”。但是这样做的话,使用代理主键的意义就失去了很多。因为,它会引起使用冗余数据后存在的所有问题,可是又没有解决代理主键的许多不足。
2
更好可读和便于理解。
3
合并相同业务实体更加容易(不同实体的主键编码不同)。
举例:两个分公司的订单,每月汇入总公司的数据库表。如果前期已经分公司订单编号区分开了,则合并数据就可以直接COPY。
如果代理主键是numeric类型的,那么前期必须定义各个分公司的订单表及子表使用不同的范围取值的代理主键。这虽然无需修改应用,但是增加了系统实施和后期维护的工作。如果代理主键是UUID或GUID这样的对象,那么则不需要。
业务主键的这一优势只限前期对不同分公司的业务主键的编码做了区分,如果没有,那么做数据合并时将更加麻烦。相反,代理主键此时反倒更具优势,因为数据合并时,只需要过滤分公司的主键而使用总公司的主键,无需修改业务编号,例如:单号、产品号。
4
数据迁移更加容易。
对于numeric类型的代理主键,在不同数据库间迁移数据时,需要重新计算被迁移实体的代理主键。
5
复杂性低和存储量少。
使用代理主键需要增加格外的索引,从而导致增加了insert的负担和需要更多的存储。
6
代理主键不是SQL的标准,不同数据库系统实现不一。因为不同数据库系统在此实现不一,导致应用跨数据库平台不方便。
可以在系统中使用ORM框架,例如:hibernate或EJB。虽然现在的ORM框架在不断完善,但是也依然有许多限制。
7
代理主键无法保证相同业务的数据被重复插入。因为代理主键是无意义的,有意义的是业务编号,当使用代理主键时,业务编号就可能重复,这破坏了关系模型。
可以为使用代理主键的实体中的“业务编号”字段添加唯一索引。
8
代理主键不能被改变。
代理主键优势
代理主键
业务主键
1
在业务发生变化时,适应性更强一些。
举例:产品编码规则发生变化。此时,产品编码不是主键,所以只需要按照新的编码规则更改产品实体表内的“业务编号”,而不会影响到其他实体。
因为产品编码是产品实体的主键,所以产品编码内容在其他实体中会作为外键,此时需要更多的工作,才能完成升级。如果那些实体已经备份到外面了,那还需要导入数据修改等工作。
当然,业务发生变化带来的升级不会仅仅update几个字段就解决的,它必然带来更多系统的考虑,比如:兼容性。
2
保证系统的一致性和系统可操作型。
举例:订单表和订单子表,订单使用“订单号”作为业务主键,订单子表使用“订单号”和序列号作为复合的业务主键。一旦订单子表的记录被其他单据引用,希望调整订单子表记录的序列号的先后次序就很麻烦了。
可以为订单子表添加一些“排序次序号”之类的字段,但是这样的字段与序列号语义上是一样的。
3
数据表连接和更新的性能更高。
举例:订单表和订单子表,订单使用“订单号”作为业务主键,订单子表使用“订单号”和序列号作为复合的业务主键。
通过业务主键做关联时,连接的开销将比代理主键大很多,而且随着业务主键(CHAR型)位数增加,性能会不断降低。相反代理主键的连接开销将相对固定,只与数据量有关,而与业务约束有关。
另外业务主键时常是复合主键,这进一步拉低了连接和更新的性能。例如更新订单子表一个记录,需要使用订单的业务编号和子项的序列号作为where条件。
4
存在主从关系时候,业务主键更新不方便。
举例:在实际应用环境中,用户也许会出错,录入错误的单号、产品号等,等发现时这些业务主键已经被多处地方使用作为外键,这时需要修改这些错误信息就会增加工作量。
5
适合与现在JAVA的ORM框架配合使用,例如Hibernate。
Hibernate的数据对象中的OID对象可以直接映射为代理主键,同时OID的新建也可以使用数据库的原生机制,从而可以被hibernate有效管理。
6
在并发环境下,更容易实现唯一的ID。
因为在代理主键是numeric类型时,可以直接使用数据库的auto increment类型的字段或依靠sequence对象产生内容。
7
系统占用的存储空间更省。
例如:CHAR(7)的业务主键和INT型的代理主键。在百万行的数量下,代理主键上的索引容量=业务主键索引存量×80%,代理主键字段存储容量=业务主键索引存储容量/2。
虽然从单表看,因为多了代理主键,所以需要更多的存储开销(代理主键字段和PK索引),但是从系统角度看,其他实体的numeric的外键将比CHAR类型的外键节省更多的空间。
总结
从关系数据库理论角度说,主键是由设计者选定的在同一实体集中区别不同实体的候选码。从这个角度看,主键的选择是客观中带有主观的,那么用有意义的实体属性还是一个无意义GUID去标识实体本没有差别,毕竟世间万物都可以给一个全世界唯一的GUID去唯一限定,只要人愿意这么做。因此,对业务主键和代理主键的取舍,更多的是需要从系统、应用环境、实体属性与关系、开发效率、系统性能和维护成本等多方面去思考