值重复了。当然,这可以通过指定不同的递增起始值来错开,但总觉得不爽啊。
SQL Server中还可以使用timestamp类型的数据来做对象标识符,这可以使对象标识对整个数据库都是唯一的,而不仅仅是对表唯一。但其优缺点与表的自增字段一样。
2.随机数字段
随机生成对象标识的方法实际就是碰运气。按照某种复杂的随机算法迅速产生对象标识,碰一碰对象标识不重复的运气。只要这种算法产生的对象标识一万年才可能重复一次,那你就可以在实际开发中应用这种算法。比如,SQL Server中提供了uniqueidentifier类型,配合NEWID()函数来产生GUID,基本上可以应用于所有主键需求了。
随机生成标识不需要在系统中维护全局量,不存在自增字段那种加锁解锁的性能开销,对于大量的并发处理来说是个福音。
同时,即使在分布式数据库应用中,不同数据库产生的随机值也是不同的。因此,在数据库的同步复制中,标识相同的就一定是同一条记录,就不会存在产生主键冲突的问题了。
不过,为了保证随机的唯一性,需要大范围的数值空间。这也使得主键字段比较大,在关联
查询的时候有一定的性能损失,判断GUID值是否相同总比判断int值是否相同要多费些功夫。
在实际应用中到底该用什么方案来产生对象标识需要根具体情况决定,以上方案仅仅是理论探讨。
接下来要注意的就是主键的索引结构的优化了。
主键都要整成聚集索引。聚集索引在SQL Server内部就是聚集表,聚集表是B树结构,索引值存在B树的中间节点中,而数据行就存放在B树的页节点上。也就是说,聚集索引和数据表其实是一个统一的整体结构。因此,聚集索引查找和定位数据的效率要比一般索引高出很多。
此外,专门主键字段值是永远都不变。聚集索引建值不变,聚集表的节点也不会调整,硬盘上的数据记录块基本不动窝的。这可以极大减少数据库碎片,除非删除数据行。数据库的碎片少了,
查询数据自然要快些。
一般来说,我们存入数据库中的数据总是有时间顺序的,我们日常查询和使用的数据也总是近期的数据。有的常用查询甚至总是按时间顺序倒排,比如,邮件列表,论坛帖子。如果主键采用的是自增字段,我们不妨将增量值设为-1或干脆搞成倒序的主键。这样,
查询的排序与扫描索引的顺序相同,毕竟硬盘的磁头总喜欢从前往后读,这会稍微提高一点读取聚集索引的速度。
同样,如果使用随机主键值的方案,我们也建议采用与时间相关的随机数值,而不是GUID。与时间相关的随机数就是,虽然主键是随机产生的,但后产生的随机数应该大于先产生的数。
为什么不用GUID呢?因为它生成的值就像顽皮的猴子,到处乱跳。于是,在每次插入记录时,聚集索引节点中相邻的值并不具有时间上的顺序。而当我们习惯性地
查询近期数据时,硬盘的磁头也需要像猴子般乱跳一通之后才能读到按时间顺序的所有数据。
如果采用有时间顺序的随机值,聚集索引插入数据时总往一个方向增加数据行的页节点,与同一时期的数据行几乎总相邻。
查询同期数据时,磁头就很少乱跳了。磁头一次可以读取一批数据,效率有将有所提升。如果您用电子显微镜去观察硬盘的表面,聚集索引的那颗B树将生长得很正很齐。
对磁头读写的优化,是完美主义的
程序员所追求的,是否采用完全看自己的心态。总之,高兴就好。当然,等将来的大容量存储设备都用上固态盘了,没磁头了,全电信号了,这些优化就都没有什么意义了。
所以呢,追求完美也是很痛苦的。吃了程