mysql - MySQL 的 ORDER BY RAND() 是如何工作的?

标签 mysql select random

我一直在研究和测试如何在 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 秒内完成了工作。他在博客中解释了它是如何工作的,所以我将跳过这个,最后转向奇怪的事情。

我的表是一个带有主键 id 和其他非索引内容(如 usernameage 等)的公用表。这是我正在努力解释的事情

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() 快速订购”之类的东西,但有针对您特定任务的解决方法。

要获取任意单个随机行,您可以像这位德国博主那样做:http://web.archive.org/web/20200211210404/http://www.roberthartung.de/mysql-order-by-rand-a-case-study-of-alternatives/ (我看不到热链接网址。如果有人看到,请随时编辑链接。)

文本是德文的,但 SQL 代码在页面下方和大白框中,因此不难看到。

基本上,他所做的是创建一个程序来完成获取有效行的工作。这会生成一个介于 0 和 max_id 之间的随机数,尝试获取一行,如果它不存在,请继续执行,直到找到一个。他允许通过将它们存储在临时表中来获取 x 数量的随机行,因此您可以重写该过程以更快地仅获取一行。

这样做的缺点是,如果你删除了很多行,并且有很大的差距,那么它很可能会错过很多次,从而使其无效。

更新:不同的执行时间

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/

I was sort of expecting to see approximately the same time for all three queries since I am always sorting on a single column. But for some reason this didn't happen. Please let me know if you any ideas about this.

这可能与索引有关。 id 被索引并且可以快速访问,而将 username 添加到结果中,意味着它需要从每一行中读取并将其放入内存表中。使用 * 它还必须将所有内容读入内存,但不需要在数据文件中跳转,这意味着不会浪费时间寻找。

这只有在存在可变长度列(varchar/text)时才会有所不同,这意味着它必须检查长度,然后跳过该长度,而不是只在每行之间跳过一个设定长度(或 0)。

关于mysql - MySQL 的 ORDER BY RAND() 是如何工作的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2663710/

相关文章:

php - 从数据库中提取用户访问级别并添加到 session 中

来自 cpanel 的 PhpMyAdmin 连接使用自定义用户

twitter-bootstrap - 模态 Bootstrap 随着更改事件 meteor 消失

sql - postgresql 聚合的聚合(sum of sum)

javascript - 由 Javascript 添加的 Img 显示 0x0 像素

javascript - simplePagination.js 不适用于 php MySQL 数据库搜索

php - Array/Dict 从 Xcode 到 JSON 到 PHP 到 mySql

mysql - 对具有多个 ID 的行求和

javascript - 每 X 小时显示两个图像,Javascript

python - 从文本文件打印随机行时出错