如果用有意义的字段做A表主键,业务中涉及更新操作,关联的表B表的外键会失效。如果设置外键约束,数据库会不允许你修改此字段值。
如果有一个无意义的id做主键,逻辑上没有任何影响,但是开发起来会方便很多
首先说一下主键和索引概念上的不同,主键只是个声明,通过哪些字段能标识出表的唯一纪录,只不过是通过唯一索引实现的。
关系型数据库中绝大部分的表,建议有唯一的主键(包括你说的自增ID或UUID方式),属于逻辑主键的范围,主要是为了程序后续开发方便,尤其是在Web应用上,这个Id可以很方便的在超链接中作为参数传递,如:editPost.do?id=123
在你说的文章标签关联表的例子中,一般会在文章展示和编辑页面中,显示关联的标签,就像segmentfault在提问的页面会显示所属的标签一样,如果没有这个id,编辑时删除一个标签,假设是通过一个Ajax请求实现的,可以按照这样的url:deleteTagOfPost.do?id=123,如果没有的话就会麻烦很多,需要把能够确定这一行记录的多个字段值都放到参数中,如:deleteTagOfPost.do?postId=123&tagId=456,显然有逻辑主键会更方便一些。
另外,用多个字段的组合作为主键来确定唯一的记录行,属于物理主键的范畴,是和业务的规则强相关的,在开发的方便性、扩展性上不如逻辑主键。
根据数据库设计的范式。主键是第一范式。你用手机号作为唯一的其实并不是完全经得起推敲,真实的世界完全有可能打破这个约束。比如说,你考虑到没有:有手机号码过期了被转让了,换了一个所有者。之前的持有人做过的事情还是要算到原来那个人的头上,此时如果手机号码是主键怎么办?你的系统就无法区分这2个都曾持有这个手机号码的人所做的事情了。 其他的情况都类似。
还有一个著名的例子就是身份证号码。身份证号码确实是对人唯一的,然而一个人是可以办理多个身份证的,号码不变。问题来了,因为系统是按照身份证号码做唯一主键的。此时,如果身份证是被盗的情况下,你是没有办法在系统里面注销的,因为新旧2个身份证的“主键”是身份证号码。那么……旧的身份证完全有效。这个时候,还好有一个身份证有效时间的东西,只有靠身份证有效期来辨识了。这就是现在这么多诈骗的由来。如果是护照,一个人办理新护照,护照号码是不会和旧护照号码相同的。而是添加一个签注,说明旧的护照号码是多少。所以,经验告诉我们。不要相信自己的直觉,业务上所谓的唯一往往都是不靠谱的,经不起时间的考研的。所以需要单独设置一个和业务无关的主键,专业术语叫做代理主键(surrogate key)