如何在 MySQL 中获取随机行(无自动增量)?

How can I get random rows in MySQL (NO autoincrement)?

我有一个大型数据库(MySQL,Aurora 无服务器),我想获取随机行(例如 1 或 5) 我知道使用 SORT BY RAND() 很慢,所以放弃了。

我也知道这里有些技巧使用行的标识符,但这仅在 id 是自动递增的整数时有效。

在我的例子中,我的数据库使用 BINARY(16) 作为 identifier/primary 键,它是一个随机生成的散列。

问题是,我应该如何检索此配置的随机行?

请注意,在我的例子中,速度比准确性更重要,所以如果它不是完全随机的行,也不是什么大问题。

我的一些想法不知道是好是坏:

-每次添加新行时,我还会添加一个使用 RAND() 的额外列,并使用该字段进行排序。问题是,这将一次又一次地生成相同的随机行。除非我定期更新该字段。好像太复杂了。

-发送 2 个请求。第一个获得最早的 createdAt 日期。然后,第二个,使用最旧日期和现在之间的随机日期对其进行排序。这不是 100% 准确,因为创建日期分布不均匀,但正如我所说,在我的用例中速度比准确性更重要。

-不知何故,使用我的 ID,因为它们已经是随机的,也许我可以从随机位开始排序。不知道。

你怎么看?你有更多的想法吗?谢谢

如果您的 ID 确实是随机的,您只需选择一个随机值并找到大于或等于该值的第一个 ID。如果您的随机值恰好大于 table 中的任何 id,请重试。

理想情况下,您可以在代码中选择随机值,但 unhex(md5(rand())) 是一种快速破解方法,应该会生成一个随机的 16 字节字符串:

select id
from yourtable
where id >= unhex(md5(rand()))
order by id
limit 1

如果您的 ID 分布非常均匀,您可以生成一个新的随机 ID,然后执行如下查询:

SELECT * FROM mytable WHERE id > ? LIMIT 1

如果您需要多个随机行(您说的是 1 到 5 之间),则重复查询,每次尝试生成一个新的随机 ID。

检查查询实际上返回了一行,以解决您的随机 ID 大于存储在 table 中的最后一个 ID 的情况。在这种情况下,请重试。

检查重复项,如果有则重试。从 50 万行中多次选择同一行应该很少见,因此重试的开销很小。

如果你想要 N 个随机行也有风险,但 table 中的总行数小于 N。如果你的重试重复逻辑没有考虑到这一点,你可以创建一个无限循环。

如果 id 不是均匀分布的,则此技术更有可能选择前面有较大间隙的行。所以它不是一个非常准确的随机发生器。