数据库主键设计原则[原创讨论]

tintown 2004-07-18 10:55:57
数据库主键设计原则


或许大家都设计过数据库,也为表定义过主键,今天我想阐述的是,应该如何正确的设计一个主键,在以往的一些资料中,都没有提及到主键设计的原则.我为此总结了一下:

1.是否要采用GUID作为主键

用GUID作主键有它的优势与不足.优势是GUID具有唯一性,在任何情况下,可以产生全球唯一的值.这是GUID最大的优势,也方便数据导入,比如要求从另一个系统中把数据导入进来,那么,不用担心,导入时,会导致主键冲突.不足是GUID值太复杂.不易记忆,因为有时,难免我们会用记录的方式,来进行记录判断.而且数据太长,影响数据库效率.GUID的产生不是以一定的次序产生,对于按主键物理排序的数据库来说,如果在记录的前部插入一条记录,可能会导致后面N次方的数据条数后移.这将导致数据插入效率.因此GUID的采用应该要慎重.

2.是否要采用自动递增的方式

对于以前谈到的主键,要求唯一性,因此大家都用自动递增的方式.这样的方式是非常不可取的.可能是为了方便插入记录时,不必去人为创建主键值.以为这样会方便,其实不是的.带来的麻烦要远远胜于这种所谓的"方便".第一:数据导入不方便,经常会有从另一系统导入数据进来,自动递增的主键,将不允许原表中的ID被导入进来.这会导致主键丢失.第二:对于象订单这样的有主外键的表来说,如果订单的"主档表"主键是自动生成的.那么在保存一个订单时,会要求对主档表与明细表同进行事务保存,而此时,先要生成一条订单,然后取出这个订单自动生成的主键,然后再把此作为明细表的一个外键,进行明细的保存.这过程中,将变以复杂而且不可行.事务如何处理.订单主档表插入记录后,要是明细保存时遇到错误,主档表记录还要进行删除.烦.插入成功以后,还要取出产生的最大值.这将是一个严重的浪费.记录多的话会影响速度,而且会存在并行插入.导致获取的记录可能是不正确的. 因此在以上的严重问题下,请不要采用自动递增方式.

3.是否要采用int型作为主键

以前大家都采用int型,都是出来主键都是数字导致的.其实我们也明白.并不是只是数字的东西就是数字型的.比如电话号码等.因此对于主键,采用int型的优势是速度快,插入,查询时都可能会比其他的方式快.但我这种快的效果也未必有多明显,比如以varchar(15)为例,物理主键排序的数据,会自动以主键进行物理数据排序.因此,就算是字符型的数据,在插入时也会插入到相应的物理位置上,也就是说,在插入时可能会影响一些速度.但在以后的查询中,速度影响不会太明显.而我要说的,不采用int型作为主键,不是说,里面不存数据.我还是建议大家在主键中存放数字,这样的排序比较要比夹杂字母的排序来的快,之所以要采用字符型,也是为以后的数据导入作准备,有一天,会要求从其他表导入数据时,可以在导入数据的主键上加一个特定字母来避免与原主键冲突.比如在导入数据的主键前加一个"N"字母.这也就不用担心,要求导入数据表中的主键是数字型还是字符型了.

4.是否采用编号来定义主键

这个问题是老生常谈了.主键设计有个原则,就是主键不应具有任何实际意义.这条其实是非常重要,有人就是觉得编号本身是唯一的,可以作为主键用,但可能会为以后带来麻烦.因为带有实际意义的字段,还是存在被修改的可能性.而对于主键最大的忌讳就是修改主键,这可能会导致非常严重的不可估计的后果.比如学生编号,平时以为永远不会修改,但修改的可能还是会存在.

还有一种,表面上是唯一的,但实际上应该是允许重复的.我举个例子,订单吧,订单编号应该是唯一吧.是的.可是会存在这样的情况,一张原来的订单是因为某个原因,要求订单作废.那好给订单的状态标识为"cancel".然后允许再次录入同样编号的订单.因此.对于这样的情况下在,虽然有效的订单编号只有一个,但在数据库角度会允许编号重复.所以不管如何,还是建议大家为表都建一个没有任何意义的主键,如ID.

因此,总结一下,我在设计主键,会采用字符型的.不采用自动递增,在新增记录时,系统生成主键值.一般为全数字进行存入,至于主键值的生成规则,可以按需求进行规则定义.如果没有特殊的要求,只是为了保持唯一,可以定义一个字段存放一个数值.在生成时,自动加一.然后再存回去.这也比从一个表中寻找最大值要来的快吧.

好了.我一时就想起这么多.有建议的一起讨论..

听棠
http://tintown.blogbus.com/
2004-7-18
...全文
356 17 打赏 收藏 转发到动态 举报
写回复
用AI写文章
17 条回复
切换为时间正序
请发表友善的回复…
发表回复
swzheng 2004-08-17
  • 打赏
  • 举报
回复
学习中....
zzcwhq 2004-07-27
  • 打赏
  • 举报
回复
学习
tintown 2004-07-18
  • 打赏
  • 举报
回复
我的建议是考虑到效率问题,我们还是不要进行新增判断了.只要我们的采用的规则比较优良.也就是同时产生相同ID的概率极低的话,我们完全没有必要每次都去进行判断.这将影响到效率.就抛出的错误而言,我觉得完全可以抛出主键冲突的友好提示信息.
whmjw 2004-07-18
  • 打赏
  • 举报
回复
一般说来,我们做增加记录之前会判断是否已经存在相应的记录,也就是是否有相同的主键值,大家一般都不会不加判断就直接增加记录的。不然产生重复的主键值引发异常,如果你没有相应的措施,就会弹出专业的错误画面,让客户看都看不懂。:)
Bob 2004-07-18
  • 打赏
  • 举报
回复
to whmjw(明年今日十年之后)

不错:)

各位继续...
tintown 2004-07-18
  • 打赏
  • 举报
回复
用时间生成是不错的生成方法.因为时间本身是一个递增的方式.所以,对于聚集索引的主键来说,插入时也是排到后面的.速度相对比较快.推荐..
whmjw 2004-07-18
  • 打赏
  • 举报
回复
我用时间来产生主键,200407081655255
2004/07/08 16:55 255ms
只要是不太频繁的插入操作都能满足
tintown 2004-07-18
  • 打赏
  • 举报
回复
对于物理主键,应该改为"聚集索引"比较合适..

至于最大值的概念,就是在另外一个表中,保存各个表主键的最大值.然后这样去取还算比较快一点.因为在这样的情况下.我们要考虑的问题,就是并发性.如果有同时操作的话,可能会取到相同的值.所以我们定义一个类.采用单线程lock(class)的方式,只允许当时只有一个进行读取.读完后,马上加一.这要比从一个表中取最大值来的快吧.

还有关于自增的不足我已经谈过了.当然,我不是说不可用.比如对于一般的数据性数据完全可以采用.只是要根据情况来.我的也只是建议..
nchen123 2004-07-18
  • 打赏
  • 举报
回复
这个问题应该请 “邹建” 谈谈看法
nchen123 2004-07-18
  • 打赏
  • 举报
回复
让我感到疑惑的是, 微软提供的几个范例都是使用的自增主键。 仅仅是为了方便吗?
nchen123 2004-07-18
  • 打赏
  • 举报
回复
也就是说专门建立一个用于生成主键的主索引表了, i see.
Bob 2004-07-18
  • 打赏
  • 举报
回复
to inelm(木野狐)

如果没有特殊的要求,只是为了保持唯一,可以定义一个字段存放一个数值.在生成时,自动加一.然后再存回去.这也比从一个表中寻找最大值要来的快吧.


我想它的意思是说在另外一个表中,保存各个表主键的最大值.
nchen123 2004-07-18
  • 打赏
  • 举报
回复
楼主能否谈谈你的主键是如何生成的?
nchen123 2004-07-18
  • 打赏
  • 举报
回复
自增
nchen123 2004-07-18
  • 打赏
  • 举报
回复
我认为子增主键也没什么不好的
Bob 2004-07-18
  • 打赏
  • 举报
回复
经验之谈,学习!

我觉得"物理主键"应该换成"聚集索引"比较好.
shangwg 2004-07-18
  • 打赏
  • 举报
回复
我用GUID做聚集索引,另外再定义其他的唯一索引,用于MS SQL Server,好处很多。
另外,SQL的页面机制可以解决性能问题。(正好是在每个页面随即插入,减少页锁定)

62,025

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术交流专区
javascript云原生 企业社区
社区管理员
  • ASP.NET
  • .Net开发者社区
  • R小R
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

.NET 社区是一个围绕开源 .NET 的开放、热情、创新、包容的技术社区。社区致力于为广大 .NET 爱好者提供一个良好的知识共享、协同互助的 .NET 技术交流环境。我们尊重不同意见,支持健康理性的辩论和互动,反对歧视和攻击。

希望和大家一起共同营造一个活跃、友好的社区氛围。

试试用AI创作助手写篇文章吧