http://www.itpub.net/thread-1133732-1-1.html
一、背景从事软件行业这些年来,我在一些软件项目的数据库表设计中,使用了几种数据表主键方式:数据库自动增量方式,GUID方式,主键流水号方式。
这里对各种方式进行一个简单的比较和建议。
数据库表的主键字段如果是自动增量,一般都是数字型(整数)。
2.2. GUID/UUID 式的主键字段 使用社会公开的算法,产生 GUID/UUID 一个全球唯一的字符串作为数据表字段。当用户插入记录到数据库表时,使用公开的算法产生一个 GUID/UUID, 并保存到数据库中。
2.3. 主键流水号 在常用的软件系统中,也常遇到使用一个数据库表来维护各个数据库表的主键值使用情。
在实际使用时,用户调用一定的接口,比如:传入数据库表名称,字段名称,软件系统的主键接口程序为用户返回一个主键流水号。
一般来说,主键流水号的数据类型是整数类型。
三、 各种主键策略的比较
评价参数 | 自动增量方式 | GUID方式 | 流水号式 |
数据插入成本 | 最好 | 较差 | 较差 |
数据查询成本 | 较好 | 较差 | 较好 |
主键字段排序方便性 | 较好 | 较差 | 较好 |
系统数据迁移唯一性 | 较差 | 最好 | 较差 |
iBatis跨数据库方面 | 较差 | 最好 | 较好 |
hibernate跨数据库方面 | 较好 | 最好 | 较好 |
多系统数据交换方面 | 较差 | 最好 | 较好 |
四、 主键策略分析 各种主键策略的优劣,见上表,我在这里再给出进一步的分析。
4.1. 自动增量方式 如果不考虑数据迁移,数据交换,跨数据库对建设的特定系统影响,使用自动增量作为主键是个不错的选择。
如果系统中既有iBatis,又有Hibernate作为持久化方案,建议选择其他方案。
4.2. GUID/UUID 作为主键 使用 GUID,UUID 作为主键策略,数据插入时候,耗费的成本可能是上面三种方案较差的。当然对于传统管理信息系统,这个问题也许并不严重。
该种策略还可能遇到一个困惑:如果在一个数据库表插入记录一条记录后,想要把最近插入的数据显示在前面,可能有点麻烦,因为该数据库表很可能没有相应的时间或者字段供排序使用,使用该主键字段来排序也不行。
4.2.1. 变种型的 GUID/UUID 为了满足在使用 GUID 策略作为主键字段的排序时候需要,我在这里提出变种的 GUID 策略。
具体操作方式,使用公开的算法生成一个 GUID 后,再进一步包装下(借用了设计模式中 GOF 的装饰者模式的思想),使用一个字符串化的日期作为 GUID 的前缀。例如:
l Guid:
0ad09547-1b14-4aab-b74d-39e7a42e39e0
l增加时间戳的GUID: 20081028172124640-0ad09547-1b14-4aab-b74d-39e7a42e39e0
l 时间转换成为字符规则:年月日时分秒毫秒 +GUID
4.2.2. 带数据来源的 变种 GUID/UUID 在这里我们就前面的思路再发散下,其实我们可以在主键上在赋予一定的数据业务意义。
我们可以在前面的变种 GUID 的基础上,再增加一个数据源标识号。比如:
A001-20081028172124640-0ad09547-1b14-4aab-b74d-39e7a42e39e0
其中 A001 是表达了我们电话号码中的区号的作用。一看该号码就知道数据来自于哪里。
这种策略在一个系统在客户的多个分支机构中部署比较有用,如果到时候这些数据汇总在一起,数据不会重复,而且也知道数据来自于那个地方,方便进一步的数据处理和数据交换。
4.3. 主键流水号 使用主键流水号策略来给系统各个数据库表分配主键值,这种策略在一个软件公司建设行业产品时比较经常见到。
4.3.1. 弊端: 接口程序每次在用户申请主键时候,从主键流水表获得一个最新主键值给使用者。这样认为的为系统并发性方面设置了一个瓶颈。
4.3.2. 带缓存的主键流水号 针对前面的这种主键流水号策略,提出主键缓存来弥补并发性的不足。
主键接口程序为每个表的主键值做一个缓存,当用户来获取主键市,接口程序从缓存中分配一个主键给使用者,当指定数据表缓存的主键分配完或者要分配完时,主键接口程序从数据库重新获得一批主键缓存起来以备用户使用。
例子:
l 主键接口程序 SEQService, 入口参数是数据表名称,字段名称,返回结果是一个整数。
l 用户申请 Book 表的 ID 字段的主键
l 主键接口程序 SEQService 使用懒汉加载模式 , 查询主键缓存去是否有该表的主键缓存数据;
l 主键缓存区中没有 Book 表的 ID 字段的主键的缓存数据,主键接口程序从数据库中申请一批主键(假设为获取数量 100 ,主键可用值为 1001 到 1100 开始),同时更新主键流水表的当前使用值。
l 主键接口程序分配分配一个主键值 (1001) 给用户使用,更新主键缓存信息(当前可用主键值为 1002 ,最大可用值为 1100 )。
这种带缓存的主键流水号策略,可以用于集群部署环境,同样有效。
这种缓存策略实际上可吧主键缓存看成是内存缓存,数据库是硬盘存储。
4.3.3. 业务流水号 != 主键流水号 在实际业务中,可能面临公文流水号也是采用连续号码的情况,公文的流水号是采用:前缀 + 公文流水 + 后缀组成。
实际上这个公文流水号充当的是“务系统逻辑主键“,并不是物理主键,为了保证该号码的连续性,需要在上面缓存的主键流水号基础上做个变通,接口程序不再采用前面的写回策略(先访问主键缓存,不满足要求,访问数据库),而是采用写通的策略,接口策略直接访问主键流水表,然后分配一个主键给使用者。
4.3.4. 变种的带步长的主键流水号 带步长的主键是:系统分配给用户的主键值不是连续的,是有一定步长的。比如:系统主键开始值为 1 ,补偿为 10 ;拿第一个使用者拿到的主键值为 1 ,第二个使用者拿到的是 11 。
l 好处:
这种策略可用于系统在总部、多公司部署,同时满足数据交换和数据整合要求。
例如:
公司甲总部的主键策略是,使用数据库表的主键开始值为 1000 ,主键步长是 10 ;公司甲的上海分公司的主键开始值为 1001 主键步长是 10 ;公司甲的东京分公司的主键开始值为 1002 键步长是 10 ;公司甲的纽约分公司的主键开始值为 1003 键步长是 10 。
根据公司甲的要求,可以在任何时候把总部和各个分公司的数据进行合并,却能保证数据不会冲突。这就是主键流水表的开始值不一样补偿一样的功劳。
l 不足:
如果系统在部署的时候,估计不足,步长设计过小,比如:上面例子中设计为 10 ,当有第 11 个分公司冒出来需要部署系统时,这时候步长就不够用了。
变通的方式,可采用前面的变种 GUID 作为主键,或者一开始就把系统主键值的补偿设计大一点,比如: 50 或者 100 。
五、 系统中的各种业务流水号 业务流水号是属于业务模型中的内容,系统数据主键流水号是系统模型中的内容。这两者既相互独立,也有一定关系
来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/4324/viewspace-1018090/,如需转载,请注明出处,否则将追究法律责任。
转载于:http://blog.itpub.net/4324/viewspace-1018090/