【发布时间】:2020-02-13 16:03:50
【问题描述】:
注意:在 Windows Server 2012 R2 Standard 上运行 MariaDB 10.2.27。
我想生成用于 MariaDB 的随机整数,所以我一直在尝试 MariaDB RAND() 函数。要么我的期望和理解偏离了基础(绝对有可能!),要么 MariaDB RAND() 函数不是很随机。
使用 BIGINT(20) 列我想生成长度不超过 16 位的随机整数,所以我使用了这个 SQL:FLOOR(RAND()*9999999999999999)+1)。我在循环中使用的确切 SQL 是:
INSERT INTO rnd_test VALUES (FLOOR(RAND()*9999999999999999)+1);
表 rnd_test 有一列是 BIGINT(20) 并且是主 ID。
使用 10^16 个数字池并考虑生日悖论,我预计在生成 10^8 个数字后发生碰撞的可能性约为 50%。显然这有一些差异,但每次我运行插入循环时,我几乎立即开始看到冲突,然后每隔 2000 或 3000 个生成的数字重复一次,有时更频繁。在生成了大约 50,000 个随机数后,我每隔几百个数字就会看到一次冲突。
认为我的理解可能非常不正确,我调整了循环的 vb.net 代码以在本地生成随机数,然后将其插入到 MariaDB 表中。我在例程顶部定义了一个新的 System.Random,然后使用它来生成随机数:
Dim r As Long = CLng(Math.Floor(rNum.NextDouble() * 9999999999999999)) + 1
通常这会更好,但仍然不如我预期的那么好。它通常会在碰撞发生之前运行大约 100,000 次迭代,然后每生成 10,000 个随机数似乎就有一到两次碰撞。有时一批 10,000 会完全没有任何碰撞。
那么,与 vb.net 函数相比,为什么 MariaDB RAND() 函数的性能如此差?
【问题讨论】:
-
我建议改用 uuid
-
同意,这就是我到现在为止需要随机 ID 时所做的事情。不幸的是,在这种情况下,我没有那个选项。我特别需要随机整数。
-
rand()产生一个只有 16 位精度的双精度数。那肯定会影响碰撞率。您应该能够通过两次调用rand()来做您想做的事情。 -
@Ian 您可以将 uuid 转换为(大)整数。
-
另一种选择:获取 uuid,然后是 uuid 的 sha1 或 md5,将其切割为 64 位(前 16 个字符),转换为 64 位整数。应该是优秀的品质。