日期:2014-05-17  浏览次数:20404 次

关于SQL主键问题,使用时间和GUID
我在设计一个模块时,由于要考虑以后数据的迁移与保证和别的系统进行数据同步。所以在设计主键时不采用标识列。而采用GUID作为主键,但是感觉GUID作为主键时,太长了,又没规律性,当数据量很大时,按照主键排序就是一个大问题了,并且连聚集索引都起不了啥作用了不是?
针对这些问题,我自己写了个函数,用于生成自己的主键。因为时间具有连续性,所以就用时间加上GUID进行生成,但GUID又太长,所以只截取了前面八位字符,构成新的主键。 方法类似如下:

 SELECT REPLACE(REPLACE(REPLACE(REPLACE(CONVERT(VARCHAR(100),GETDATE(),21),'-',''),':',''),'.',''),' ','')+'_'+left(CAST(NEWID() AS VARCHAR(36)),8) 

不知道这样好不好,会有什么问题没,希望有经验的前辈指教,谢谢~
sql 经验 主键

------解决方案--------------------
不要用newid()生成,可以用CREATE TABLE a (a UNIQUEIDENTIFIER)这种来生成,但是我觉得用业务键来做主键比较好
------解决方案--------------------
用newid生成的,确实是唯一的,但是占36个字节,太长了,

你现在用时间+newid,然后取前8位,也会占用26个字符,也不少,这样倒是有点规律性了,至少前面部分能知道日期和时间,也能达到唯一性。

这样一考虑也算是个折中把,上面说要用UNIQUEIDENTIFIER,也可以达到唯一性,占用16字节,但值是无序,也无意义的值,不太适合你的情况。
------解决方案--------------------
引用:
而我现在出来的是   20131017115630280_43AD9A64    有26个字符, 聚集索引的物理地址与排序的地址不就一致了?


你说的没错,因为你前半部分的日期是不断增大的,所以聚集索引和实际排序后,是一致的。


------解决方案--------------------
生成的UNIQUEIDENTIFIER类型的值好像是无序的哈,返回结果也是无序的
------解决方案--------------------
其实不是完全无序的
CREATE TABLE myTable (ColumnA uniqueidentifier DEFAULT NEWSEQUENTIALID()) 
INSERT INTO myTable DEFAULT VALUES
GO 10

SELECT * FROM myTable

/*
ColumnA
------------------------------------
360E7FF1-EF36-E311-BEAB-A41731BD8A1E
370E7FF1-EF36-E311-BEAB-A41731BD8A1E
380E7FF1-EF36-E311-BEAB-A41731BD8A1E
390E7FF1-EF36-E311-BEAB-A41731BD8A1E
3A0E7FF1-EF36-E311-BEAB-A41731BD8A1E
3B0E7FF1-EF36-E311-BEAB-A41731BD8A1E
3C0E7FF1-EF36-E311-BEAB-A41731BD8A1E
3D0E7FF1-EF36-E311-BEAB-A41731BD8A1E
3E0E7FF1-EF36-E311-BEAB-A41731BD8A1E
3F0E7FF1-EF36-E311-BEAB-A41731BD8A1E
*/

------解决方案--------------------
可以吧,这样既保证了聚集索引的整体有序,避免页拆分,又有一定的可读性
------解决方案--------------------
如果是我,就设计三个字段,GUID太长没关系。
1 自动编号,每台机器各自编号
2 GUID
3 客户端ID,数据来源机器ID
需要注意:
每台机器上的数据的自动编号和顺序是不一致的,
但同一个客户端ID的数据的顺序是一致的。

------解决方案--------------------
所以我说用业务键会比较合适
------解决方案--------------------
可能算吧,好像我上一家公司做ERP的,表里面几乎没有用什么自增键,都是用货号+其他什么号来标识,这种复合主键即使去到oracle也合适。并且基本上不存在重复或者冲突的问题
------解决方案--------------------
建议:

1.使用业务数据做主键
2.每行数据增加guid列,以备数据复制迁移等。

[AdventureWorks2012].[Sales].[SalesOrderHeader] 就有[rowguid]列。

有什么办法可以清理掉日志里面的部分操作?解决办法