我需要生成一个唯一的ID,并考虑Guid.NewGuid
来做这件事,它生成的形式如下:
0fe66778-c4a8-4f93-9bda-366224df6f11
对于它最终驻留的字符串类型数据库列来说,这有点长,所以我打算截断它。
问题是:就唯一性而言,GUID的一端是否比其他一端更可取?我应该剪掉开头、结尾,还是从中间去掉部分?或者这并不重要?
可以使用base64字符串来节省空间:
var g = Guid.NewGuid();
var s = Convert.ToBase64String(g.ToByteArray());
Console.WriteLine(g);
Console.WriteLine(s);
这将为您节省12个字符(如果没有使用连字符则为8个字符)
全部保留。
从上面的链接:
* Four bits to encode the computer number, * 56 bits for the timestamp, and * four bits as a uniquifier.
你可以重新定义Guid,使其大小适合你的需要。
如果GUID只是一个随机数,您可以保留任意的比特子集,并且可以使用"生日算法"计算一定百分比的碰撞几率:
double numBirthdays = 365; // set to e.g. 18446744073709551616d for 64 bits
double numPeople = 23; // set to the maximum number of GUIDs you intend to store
double probability = 1; // that all birthdays are different
for (int x = 1; x < numPeople; x++)
probability *= (double)(numBirthdays - x) / numBirthdays;
Console.WriteLine("Probability that two people have the same birthday:");
Console.WriteLine((1 - probability).ToString());
然而,通常发生碰撞的概率更高,因为事实上,guid通常不是随机的。根据维基百科的GUID文章,有五种类型的GUID。第13位指定您拥有的GUID类型,因此它往往变化不大,并且第17位的前两位始终固定为01
。
对于每种类型的GUID,您将获得不同程度的随机性。版本4(第13位数字= 4)是完全随机的,除了数字13和17;版本3和5实际上是随机的,因为它们是加密哈希;虽然版本1和版本2大多不是随机的,但某些部分在实际情况下是相当随机的。版本1和版本2 guid的一个"问题"是,许多guid可能来自同一台机器,在这种情况下,将有大量相同的位(特别是,最后48位和许多时间位将是相同的)。或者,如果在不同的机器上同时创建了许多guid,那么时间位之间可能会发生冲突。祝你能安全地截断它。
我有一个情况,我的软件只支持64位的唯一id,所以我不能直接使用guid。幸运的是,所有的guid都是类型4,所以我可以得到64位随机或几乎随机的。我有200万条记录要存储,生日算法表明,碰撞的概率为1.08420141198273 x 10^-07(64位)和0.007(0.7%)(48位)。这应该被认为是最好的情况,因为随机性的减少通常会增加碰撞的概率。
我认为在理论上,将来可能会有比现在定义的更多的GUID类型存在,所以不可能有一个面向未来的截断算法。
我同意Rob - 保留所有
但是既然你说你要进入数据库,我想我应该指出,仅仅使用Guid并不一定意味着它可以很好地在数据库中建立索引。因此,NHibernate开发人员创建了一个对数据库更友好的Guid.Comb
算法。
请参阅NHibernate的POID生成器和Guid算法文档获取更多信息。
注意: Guid。梳子是为了提高MsSQL
截断GUID是一个坏主意,请参阅本文了解原因。
您应该考虑生成更短的GUID,因为google提供了一些解决方案。这些解决方案似乎涉及采用GUID并将其更改为完整的255位ascii。