数据唯一性字段的探讨
2001-07-11 09:44出处:yesky作者:jame【我要评论】
[导读]数据库开发中,经常会用到的一个概念的数据表的唯一性字段,当连接表、数据索引的时候通常作为数据表主关键字的唯一性字段是重要的数据特征......
数据库开发中,经常会用到的一个概念的数据表的唯一性字段,当连接表、数据索引的时候通常作为数据表主关键字的唯一性字段是重要的数据特征。按照一般数据库设计的要求,该字段需要在保证应用的前提下占用空间最小以提高数据处理速度。所以一般采用LONGINT(长整型4个字节)来作为这个数据唯一性字段。该字段的容量为2的31次方。对于一般应用来说已经足够了。
由于我们操作唯一性字段的时候为了更快的得到下一个需要增加的字段值,往往采用直接最大值+1的操作,所以这个时候就带来一个问题:如果我们只是每次简单的通过最大值+1得到下一个唯一字段的值,那么当数据库大量进行删除和增加操作的时候就会更加快的达到长整型数值的上限。这个时候使用长整型数据表的上限就不是存储2的31次方个纪录而是可以进行2的31次方次增加和删除操作了。
尽管后者的上限也是在平常应用中很难达到的(它的含义就是:如果每天进行100万次增加和删除操作也要5年多才能达到;或者说每秒进行68次增加和删除操作可以连续进行1年)但是毕竟没有完全利用长整型的数据存储量,考虑到以后的扩展性还是需要对如何得到唯一性字段的值进行优化。
这里还有一个附加问题,为什么需要自己计算一个唯一性字段的值而不利用某些数据库系统提供的自动增长字段。如果考虑到自动增长字段不是每种数据库都提供了,为了兼容性考虑就会放弃掉这个简单的答案。而且这样也会有数值使用上的浪费。
如何解决这个问题呢?
比较容易想到的是记住每次删除的唯一性字段值然后当下次插入新的纪录的时候,使用这个被删除的唯一性字段值.
还有一个方法就是每次产生新的唯一性字段值的时候,在已经存在的值中进行一次搜索,如果找到了没有使用的值就使用它。
但是从我们的叙述也可以看到,这两种办法都存在了效率和空间两方面的浪费。由于需要使用某种方法来找到已经使用却被删除的唯一性字段值的可能性的概率很低更加增加了这种浪费的低效。
然后可以想到的是,其实造成长整型存储容量不能被全部使用的直接原因是删除操作,只要对删除操作进行处理就可以防止大量的唯一性字段值被忽略使用。
比如:每次删除一个纪录的时候就找到当前存在的最大的唯一性字段值,如果该值不是当前被删除纪录的唯一性字段值,那么就可以删除当前纪录的同时把拥有最大唯一性字段值的纪录的唯一性字段值改变为被删除纪录的唯一性字段值。
这个想法在每次删除一条或者几条纪录的时候没有问题,假如是同时大量删除数据,那么有可能会出现效率的降低。
另外一个可以考虑的方法比较有局限性。如果对于数据存储容量比较小,但是经常进行大量删除和增加操作的数据库系统,可以采用在系统后台全部更新每个纪录的唯一性字段值的方法。
例如:我们可以把这种数据库中每个纪录的唯一性字段值转换为该纪录按照某种顺序排序的时候的序号。
综合以上的考虑,我们发现对于处理唯一性字段值,针对不同的情况可以有多种处理的搭配来达到最好的效果。效率和空间的统一。(可以注明的是对于某些特殊应用,也可以对于使用短整型数值作为唯一性字段值提供参考)
下面我们针对一个拥有一下条件的系统进行分析和设计,同时给出处理唯一性字段值的伪代码。
该系统包含大量用户,每个用户都有可能大量操作数据纪录。同时也有可能同时大量删除数据。尽管可能最终数据操作数量达到长整型数值上限的可能不大,但是也有可能会出现。
因此进行如下的处理来得到一个唯一性字段值。该唯一性字段值用id表示
<1>增加纪录的时候
| if MAX(id) < 2^31 then begin file://如果现在数据库唯一性字段的最大值<2的31次方 return MAX(id) + 1; file://直接返回当前最大id值+1 end else begin if MAXRECORDCOUNT < 2500 then begin file://如果目前数据库的记录数< 2500 For i=0 to MAXRECORDCOUNT -1 do begin REPLACE RECORD(i).ID WITH i; file://把每个纪录的ID用记录序号更换 end; end else begin For i=0 to (MAXRECORDCOUNT mod 2500) do begin k := 0; READRECORDS FROM i*2500+k TO (i+1)2500; file://读取前2500个纪录的id If LOCATEUNUSEDRECORD then Return(UNUSEDid) k := 1; end; end; end; |
<2>删除纪录的时候
if DELETEONERECORD then begin file://如果删除一条纪录
REPLACE MAX(id) WITH DELETED(id); file://把目前最大的id替换为被删除的id
end;
我们也可以设置一个标志位,来标明现在最大的id已经是2的31次方了,而根据标志位来判断是否需要在删除纪录的时候进行id的替换工作。
以上仅仅是个人对于唯一性字段值使用和开发的一点浅见,希望大家有更好的意见和看法。欢迎和我交流。
我的Email: jamewe@yahoo.com.cn





![[图]黑莓BB10系统主屏界面抢先看:MeeGo泪流满面](http://img.bbs.chinabyte.com/data/attachment/forum/201205/15/204553bbsbyasz3k3kahn6.jpg)


![[图]《暗黑3》开服9小时](http://img.bbs.chinabyte.com/data/attachment/forum/201205/15/105452z164x1irp6ez4rxi.jpg)


