“胡说八道” DATABASE 主键设计

探讨了在ORACLE数据库中使用自增序列作为主键的潜在问题,特别是在多个表间共享主键时可能出现的数据不一致性。文章对比了自增序列与GUID等非自增序列在主键设计上的优劣,强调了主键设计应考虑数据库特性、业务需求、数据融合及性能等因素。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目是胡说八道,当然是打引号的,So How do we design the primary key in tables ? That's a complecated question.

Why?  下面就举个例子来说说 这个主键高出的 “Joke”

先画个图

图中有四个表,最上面的是基础表,下面三个表由于功能不同,部分数据不同,但基本的数据是由最上面的表给出的。

先强调这个表是基于ORACLE 11G 的,并且是自增列,自增列,自增列,重要的说三遍。

按照程序的设计之初,四个表的主键应相同的,而问题在于,HOW ,HOW ,HOW could you use the sequence ? 

知道ORACLE 的原理的,都知道ORACLE 的表都是 HEAP表,而自增序列在ORALCE 中对物理性,没有任何的意义,而想通过自增列来四个表的主键进行一个 “绑定”, 这显然就是“一个巨婴”。 问题也就由此而来,调用ORACLE 序列然后得到一个值,将值插入到主键的位置,看上去没有什么错,很多人都这么设计,但这个系统中关键的问题是,你还有表需要公用主键,你如何保证三个表的序列 ANY TIME ANY WHERE 都能一致,天真的太假了。

所以当其中一个表的自增序列由于某些原因,变得“另类”,并且程序不严谨的情况下,那三个表之间的数据可就要不一致了,而且不一致的厉害。程序由于其中一个表主键的重复,无法插入数据后,(如果三个表的插入在一个事务,那数据不会不一致,只会报错,回滚,错的还不至于那么厉害,可惜第三方的开发哪管你死活,功能完成就可以),程序就反复的插入数据,结果就是一个表中没数据,另外两个表全是不应插入的数据。

所以我在听到这个时候,心里悠然而生的疑问,为什么要用自增序列?

这样的情况如果使用 非自增序列,并且由某些成熟的框架生成的 “ID”,例如GUID,或者根据时间戳加上一些其他值,经过算法出来的“唯一值”,这问题估计就算是程序有BUG ,也不会出现三个表数据不一致的情况了,因为人为根本就不能随意模仿出ID值,如果模仿出那这个行为就“不单纯” 了。

OK ,话归主体,数据库的主键设计其实是一个很重要的事情,他关乎,你程序的性能,你程序的高可用,你程序是不是要分库分表,你程序的逻辑性,你数据的大数据融合, 可以说一个主键关乎的问题,可没有那么简单。

ORACLE ,MYSQL , SQL SERVER , POSTGRESQL ,MONGODB,每个数据库都有自己的主键建议,例如 MYSQL 强烈,强烈,强烈,建议使用自增ID或有序的ID ,因为这和他目前的数据存储结构有关,你当然可以在MYSQL上用 UUID ,或者其他不规则,毫无顺序的ID 生成器来作为 MYSQL的主键,但你违背了MYSQL (5.7,没说8.0),底层数据存储结构,你必然要付出代价。 翻翻之前我的一篇文章,也是第三方开发出的MYSQL 表,惨不忍睹,性能低下,可以上的了反面教材的“典范”。

同样,类似 ORACLE , POSTGRESQL,你真的不用向 MYSQL 那样考虑你ID 的物理顺序性,因为HEAP 表根本就没有顺序性。但这不意味这,你主键的设置,可以很任性。

我见过主键设置为 CHAR(255) 的案例,我是在是无力吐槽,设计成这样的 ,建议转行吧,思维太超越,画油画比较适合,印象派,让人印象深刻。

估计有人已经向 asking, 到底主键怎么设计

一、 根据你使用数据库的属性来开始最基本的发散性思维 (首先你要知道你使用数据库的底层存储对你主键倾向性)

二、根据业务,在符合数据库的原理后,就要面向业务了,如果你使用的表可能未来会进行分布式操作,那你的主键必然不能是简单的数字顺序性的递增

三、 你的主键到底参与业务与否,(支持参与的就不必说了理由很多),还有一种不支持主键和业务进行绑定的。主键不参与业务绑定的,主要的原因可能有以下

1  开发初期,或业务逻辑不稳定期,一个主键的设立,尤其对于SQL SERVER 和 MYSQL ,如果你选择不好,后期想在改那是很困难的一件事情,对于其他数据库主键的选择错误也不是说随意改,就算OK,你业务逻辑是多经不起推敲。

2  主键和数据库的类型绑定,可能限制你使用主键,例如你很想在MYSQL中使用无规律的主键作为业务主键,而MYSQL的主键设计,不建议你这样做,你是换个数据库还是换个主键的设计方法,其实都不用,你需要理解,业务主键,和逻辑主键的关系,困扰你的问题就可以避免了。

3 后期数据融合的问题,要知道使用MYSQL 的用户在分库分表后,都可能会有后一步,就是数据的在融合,例如你分库是解决了,业务高并发的插入,和业务简单逻辑的查询,而后期你需要做一些数据汇总的查询,那你估计就傻在那了,当初的主键设计不合理,让你的数据融合变得和吃了耗子药一样的,上不了天,下不了地,妥妥的卡在中间,那滋味是相当的"enjoyment"。

四、尽量的小,尽量的不对插入和主键查询产生困扰。

其实关于主键的话题还能继续,例如主键生成器,主键生成池,分库分表主键设计,那种主键在高并发时插入的速度更快。

结尾留下一个问题

下面是SQL SERVER 的三种ID 自动生成的方法,第一种类似UUID,第二种类似GUID,第三种就不必说了,地球人都知道。The question , which one is better than others ?

create table tblGUID(RecID uniqueidentifier default newid(),  SessionID int)

create table tblSeqGUID(RecID uniqueidentifier default newsequentialid(),  SessionID int)

create table tblBigINT(RecID int identity(1,1), , SessionID int)

聪明的你是不是已经有答案了?

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值