【发布时间】:2011-02-09 11:02:09
【问题描述】:
我一直在研究和测试如何在 MySQL 中进行快速随机选择。在此过程中,我遇到了一些意想不到的结果,现在我不确定我是否知道 ORDER BY RAND() 的真正工作原理。
我一直认为,当您对表执行 ORDER BY RAND() 时,MySQL 会向表中添加一个新列,该列填充有随机值,然后按该列对数据进行排序,然后例如您采用随机到达的上述值。我做了很多谷歌搜索和测试,最后发现查询Jay offers in his blog确实是最快的解决方案:
SELECT * FROM Table T JOIN (SELECT CEIL(MAX(ID)*RAND()) AS ID FROM Table) AS x ON T.ID >= x.ID LIMIT 1;
虽然普通 ORDER BY RAND() 在我的测试表上需要 30-40 秒,但他的查询在 0.1 秒内完成了工作。他在博客中解释了它是如何工作的,所以我将跳过这个,最后转向奇怪的事情。
我的表是一个普通表,其中包含 PRIMARY KEY id 和其他非索引内容,如 username、age 等。这是我正在努力解释的事情
SELECT * FROM table ORDER BY RAND() LIMIT 1; /*30-40 seconds*/
SELECT id FROM table ORDER BY RAND() LIMIT 1; /*0.25 seconds*/
SELECT id, username FROM table ORDER BY RAND() LIMIT 1; /*90 seconds*/
我有点期望看到所有三个查询的时间大致相同,因为我总是在单个列上进行排序。但由于某种原因,这并没有发生。如果您对此有任何想法,请告诉我。我有一个项目需要快速 ORDER BY RAND() 并且我个人更喜欢使用
SELECT id FROM table ORDER BY RAND() LIMIT 1;
SELECT * FROM table WHERE id=ID_FROM_PREVIOUS_QUERY LIMIT 1;
是的,它比 Jay 的方法慢,但是它更小,更容易理解。我的查询相当大,有几个 JOIN 和 WHERE 子句,虽然 Jay 的方法仍然有效,但查询变得非常大和复杂,因为我需要使用 JOINed(在他的查询中称为 x)子请求中的所有 JOIN 和 WHERE。
感谢您的宝贵时间!
【问题讨论】:
-
作为研究的一部分,您还可以考虑在表中添加一个随机数列,而不是按 rand() 排序。然后您可以通过选择大于随机数的第一行来随机选择行。
-
@MichaelPetito 这将不起作用,因为您可能希望在每个查询中使用不同的随机“组”随机行,而您的解决方案将提供相同的“组”随机行。