要求在用户点击提交按钮时向数据库发送唯一ID。因此,我使用了JavaScript的Math.random
方法。我只想知道获取相同数字的机会或可能性有多大,并且使用Math.random
需要什么位数。
要求在用户点击提交按钮时向数据库发送唯一ID。因此,我使用了JavaScript的Math.random
方法。我只想知道获取相同数字的机会或可能性有多大,并且使用Math.random
需要什么位数。
你将会遇到生日问题:尽管有366种可能的生日,但只要在一个房间里聚集26个人,就有超过50%的概率会有两个人出生日期相同。通常情况下,当你的数量接近样本大小的平方根时(26接近于366的平方根),碰撞是很可能发生的。
Javascript的Math.random()函数大约有52位的随机性。因此,当你的记录数接近2 ** 26(大约为6000万)时,发生碰撞的可能性就会增加,对于数据库来说是一个相当适中的规模。
为了避免碰撞,应该使用至少128位、最好256位的加密安全伪随机数生成器(PRNG)。这方面可能已经有现成的UUID库可用。
对于给定数量的键和键空间,碰撞的近似概率如下:
1 - exp((-k * (k-1))/(2 * N))
因此,对于100万条记录,N=2 ** 52,如果我算得正确,这大约是1/9000的概率。这还假设Javascript的Math.random()函数真正利用了它可以获得的所有52位随机性......这也是我不会做出的假设。
不要这样做。相信(多个)客户端产生独特值是不可行的。
即使每个客户端都能保证生成唯一值,你仍可能会有两个客户端生成相同的值。由于大多数伪随机数生成器都是基于当前时间种子化的,随着用户数量的增加,这种情况会变得更加普遍。
如果你正在创建数据库记录,你的数据库应该提供类似于此的功能。大多数或所有SQL数据库都有自动增量概念,而许多NoSQL数据库也有相应的概念(例如,Mongo对ID有一个)。允许数据库处理这些数据可以提高性能(它可以设置索引并分配空间来处理这些ID),而且DB可以最终决定数据,因此可以保证ID唯一性。
如果没有这样的功能,那么你可以让服务器端生成一些唯一标识符(例如UUID)并使用它们。让服务器端处理并使用已知的良好算法(例如Type 4 UUID),可以保证足够的随机性,从而避免发生冲突。请注意,与顺序ID相比,使用UUIDs(除非你的数据库为它们提供了类型)将具有非常不同的索引性能。
crypto.getRandomValues
可以缓解碰撞问题,支持的浏览器包括IE11+;它保证使用良好的熵源进行种子生成(因此不是当前时间)。但客户端随机值的真正问题在于它们容易被篡改。 - Retsam我更喜欢使用时间戳、客户端或用户相关标识生成自己的随机数。