引入
上期我们介绍了关系模型和关系数据库,那么这个“关系”到底是由谁来决定的呢?难道我处理数据的时候还要看某个值原本的意义吗?
笔者认为一般来说,数据库的使用者应当对数据有一定的认知,但是如果所谓的数据关系是靠使用者的理解来自行定义,恐怕有失严谨。
毕竟换个人操作,理解就有可能不一样嘛,那关系数据库各个表的关系就随之变化了?显然不现实。
事实上,我们的关系数据库中,关系是由“主键”和“外键”来维护的。今天我们就主要来看看主键——
1.主键定义
关于关系表,我们有个很重要的约束——任意两条记录不能完全相同(两条数据至少需要有一个字段的值不同,以此来区分这两条记录)。
当然,这个规则不能仅仅由我们输入的时候注意不重复就行了。我们在设计表的时候就需要考虑好,我们在这个表里要以哪个字段作为我们的“区分字段”,任意两条记录在这个字段都不能重复。
术语上,我们把这个“区分字段”叫做“主键”
2.主键的意义
概况一下定义,主键是“任意两条数据都不重复的字段”。它可以理解成是用来作每条数据的身份证的,我们可以通过主键的值定位到任何一条记录。
所以我们也可以理解,为什么说主键一般不要修改,因为身份证换了,不能再用以前的身份证定位到你了,自然会连带出现一系列麻烦的问题。
3.主键的选取
主键非常重要,选取主键是个学问。首先你要保证它不会重复(所以可想而知,用人的名字作为主键就不大合适。张伟你说对不对?)
此外,还要保证其不会经常更新。比如你拿手机号当主键也不合适,人家换个手机号你就得把数据库大改特改。
所以我们的主键选取有一个原则:不使用和业务有关的字段,比如手机号、邮箱,甚至居民身份证号(因为身份证是业务,有可能变更)
那么建议怎么定义和选择主键呢?我们大致可以参考这两个方案:
自增型整数。数据库在某条数据插入的时候自动分配数据一个整数,整数自动地随着数据的增多而增大,保证每个都不同,而且不涉及业务,不需要改变。
全局唯一GUID。通过GUID算法,通过获取网卡mac地址、时间戳等原始数据生成一串不重复的字符串,类似8f55d96b-8acc-4636-8cb8-76bf8abc2f57
这样的十六进制码。
以上两种方法各有优劣。 比如自增型整数理解简单,生成方便,可以满足绝大多数需求。但是很明显,这种方法生成的主键位数不是确定的,会显得不统一;且INT类型的数据最大只能到21亿左右(上限2147483647)。而GUID类型相对来说没有自增型的那些优点,但是主键可以格式统一,并且最高可以支持到922亿亿条记录。
4.联合主键
主键只有一个,如果主键有多个,怎么完成所谓“唯一身份标识”的作用呢?
但是并不代表主键只能是一个字段
关系数据库事实上可以支持我们设置多个字段来实现“唯一标识功能”。这就是联合主键
联合主键与普通主键的区别就在于,联合主键只要不是所有主键列都重复就行。比如我们设置id1 和 id2两个主键:
id1 | id2 | columns... |
1 | x | ... |
2 | x | ... |
2 | y | ... |
如表,虽然di1和id2都有重复的情况出现,但是我们设置的是联合主键,id1和id2没有同时重复的情况出现,这个主键就是合理的。
有意思的是,我们一开始提到关系数据库的规则是“任意两条记录不能完全相同”,由此看来整张数据表都可以看成一个大的联合主键了(doge),那我们需要主键干嘛呢?
可千万别学傻了,面对这个问题,理解主键存在的意义就很重要了。结合我们一开始推导的“主键是为了区分数据”、“主键是数据的唯一标识”,可以看出设置太多联合主键是没有意义的,提升了复杂度,属于是南辕北辙了
少而准,达到目的,才是好的主键