转自于:http://blog.csdn.net/haizhongyun/article/details/8056578
关于本文一些词的说明:
单一主键:逻辑主键
复合主键:联合主键,业务主键
今天在做项目的数据库设计时,突然发现自己在表的主键设置方面太过片面,对于逻辑主键和联合主键的理解也很少。索性上网百度了一下,看到了一些论坛中的兄弟们的讨论,其中很多的分析让我顿时清醒了很多。下面开始贴上一些人的观点和分析,如果原作者看到本文,发现有不妥之处,请邮件告之。
网友goldrain说:
我倒不反对业务主键,但只指单一字段做主键,比如很多登陆系统,常就用loginName做用户表主键,而且这么做很方便,我觉得只要是值唯一而且不改动的字段就可以做主键; 不过觉得联合主键确实多余,这时用单一字段的逻辑主键取代联合主键,对定位记录的速度,对开发特别是hibernate开发会很方便; 我的观点都是从自己开发方便角度讲的.
网友magician说:
我觉得逻辑主键和联合主键用途不一样:
如一个囚犯,进监狱就会给他一个逻辑主键,比如9527,但他外面混的朋友可能并不知道这个逻辑主键,而只有他的一些其他信息,比如姓名、年龄、外貌、所做的事情等等,这些感观上的东西构成的可以认为是联合主键。
如何评价这两者谁好?我只能说,应用范围不一样。但不可否认,9527非常清晰!(当然我不愿意人家这样叫我.......)
还有就是,你说用联合主键做出来的东西运行得很好,所以你没有道理要用逻辑主键。从你的实际情况而言,你这么说没错,但从逻辑思维的角度,你大错而特错:存在并不一定合理。不过在你自己还没有找到使用逻辑主键的理由之前,我完全赞同你不要去修改现有系统这一英明的决定。
再者,浪费很多空间?呵呵,我不认为一个类似于银行这样系统还会在于有一个字段引起的空间问题,假如这个字段给你带来的是设计的合理和操作的快捷的话,请注意我用的是假如。当然,你可以更感性的了解一些数据,看看每个表多一个int字段会带来多大的空间上的损失。我觉得空间这个东西,不是在这个层面需要考虑的问题。其实,我现在在做任何系统的设计,都不会考虑硬件空间的问题。
至于更具体,比如对你们的系统性能究竟有多大影响,设计上有多大影响,现有系统改动量有多大,那是你应该考虑的问题。
另:Hibernate不一定要用逻辑主键 再另:不一定要用Hibernate!
网友xiaoyu说:
用逻辑还是业务,随便你的,不过旧系统是不要用HB,HB也支持复合主键.
主要是作了主键后就不能修改,这个蛮麻烦的.....唉..
记得那年,公司有出了一个主意,想要一个定单的系统,于是我就去调研(公司只有我一个开发员,客户就是下面的员工),我说产口是不是有一个固定的产品号,是不是不会重复的(好象地球人都知道),那定单是不是有一个订单号,也是固定的,不会重复,她们回答的时候是多么爽快呀(好象在逗小孩子).
我就用Access建了表(就公司用,所以没有选择其它的数据库),主键:用了产品号,用了订单号.又因为她们超喜欢excel,就用了VBA.....
系统运行了一段时间,后来产品的编号要改掉了,全部的产品号要在前面多加个LP开头的.....我顿时..........@#$%^&*( OK,我只好用insert into XXXX (select XXX) (还是产品号为主键). . . 网友xj2ee说:
1、从纯数据库设计的角度来看:
使用业务主键是自然的选择,但如果业务发生变化引起业务主键的变化怎么办?(xiaoyu举的例子),所以引入逻辑主键id(当然不是每张表都要),浪费空间之说我认为是没有必要考虑的,存储技术的发展能容忍这点小浪费。而且单一的id在多表关联时,显然比复合主键有更好的性能。
2、从WEB应用开发的角度来看:
用逻辑主键你只需要在页面和后台之间传递一个单一的参数,简化了开发工作,而且有较高的查询效率。
3、从Hibernate应用的角度来说:
复合主键需要更多的处理,性能不高,所以Hibernate不提倡用复合主键。
补充网上一些其他讨论:
多对多关系建立中间表一定要用联合主键么?
在做一个租赁系统,有一张用户信息表t_user,一张车辆信息表t_car,做车辆的租赁单想通过一个中间表来实现,但我想用订单号(时间相关)来作为主键,这种情况下可不可以放弃使用联合主键?而且顺便请教一下,使用联合主键的好处?
你这个例子不能用联合主键,只能订单号或者自增id作主键
因为这个"租赁单"表是核心的业务实体,在现实中的确会有一张纸制的租赁单据,它不是因为车辆和用户才存在的。
以后如果业务扩展,比如新增了业务员表、分店表要和租赁单表关联,你之前设计的联合主键就失败了。
补充:
1. 一张表可以没有主键;
2. 一张表可以有多个主键(联合主键);(通常在多对多关系中使用,写在多对多的中间表中,注意其中的奥妙)
比如说一个学生管理系统,一个学生可以选多门课,一门可以有多个学生来选,学生表学号stu_id是主键,课程表cou_id是主键,多对多关系要用中间表---“学生选课表”enrol来实现数据的关联,enrolyou两种设计方式,第一种是:
CREATE TABLE enrol (
cou_id int ,
stu_id int ,
accept varchar(32) ,
score varchar(32) ,
CONSTRAINT enrol_ibfk_1 FOREIGN KEY (cou_id) REFERENCES course (cou_id),
CONSTRAINT enrol_ibfk_2 FOREIGN KEY (stu_id) REFERENCES student (stu_id),
primary key(class_id,stu_id)
);
就是采用复合主键,第二种是:
CREATE TABLE enrol (
enrol_id int primary key,
cou_id int ,
stu_id int ,
accept varchar(32) ,
score varchar(32) ,
CONSTRAINT enrol_ibfk_1 FOREIGN KEY (cou_id) REFERENCES course (cou_id),
CONSTRAINT enrol_ibfk_2 FOREIGN KEY (stu_id) REFERENCES student (stu_id)
);
采用了一个单独的主键,stu_id和cou_id知识普通的字段。
这两种方式哪个好?为什么?
现在都不建议使用复合主键了吗,但是不使用复合主键的话,没法保证学生不会重复选课。