当前位置: 首页 > 面试题库 >

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

东门航
2023-03-14
问题内容

我一直在研究和测试如何在MySQL中进行快速随机选择。在此过程中,我遇到了一些意外的结果,现在我不确定我是否知道ORDER BY RAND()的工作原理。

我一直以为,当您在表上执行ORDER BY
RAND()时,MySQL会向表中添加一个新列,该列中填充有随机值,然后按该列对数据进行排序,然后,例如,您采用上面随机获得的值。我已经进行了大量的Google搜索和测试,最后发现Jay在他的博客中提供的查询确实是最快的解决方案:

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和其他非索引的东西一样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 : //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秒 /

SELECT ID FROM table ORDER BY RAND()LIMIT 1; / 0.25秒 /

SELECT ID,用户名,来自表ORDER BY RAND()LIMIT 1;/ 90秒 /

我一直希望对所有三个查询都看到大致相同的时间,因为我总是在单个列上进行排序。但是由于某种原因,这没有发生。如果您对此有任何想法,请告诉我。

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

仅当存在可变长度的列(varchar / text)时,这才有所不同,这意味着必须先检查长度,然后跳过该长度,而不是仅跳过每行之间的设置长度(或0)。



 类似资料:
  • 问题内容: 我知道SQL的语法如下: 但是,我不了解它是如何工作的,可能是因为我正在考虑将其视为声明。 例如,如果我在表中有一个字段,其中包含诸如“经理”,“兼职”等名称,那么如何根据角色生成一个具有不同编号的字段。在此示例中,“如果user_role =’经理’,则role_order = 5”。 请注意,我正在寻找一个 教男人如何钓鱼的方法, 而不是 给男人一个钓鱼的方法 。 问题答案: 更像

  • 问题内容: 创建视图时,我基本上是在创建一个新表,当其中一个表中的数据发生变化时,该表将自动进行处理。那是对的吗? 另外,为什么我不能在视图中使用子查询? 问题答案: 视图的工作方式 类似于表 ,但不是表。它永远不存在;它只是在引用视图名称时运行的准备好的SQL语句。IE浏览器: …相当于运行: MySQLDump将永远不会包含要插入视图中的行… 另外,为什么我不能在视图中使用子查询???? 遗憾

  • 问题内容: 我对MySQL索引的工作方式非常感兴趣,更具体地说,它们如何在不扫描整个表的情况下返回请求的数据? 我知道这是题外话,但是如果有人可以向我详细解释一下,我将非常非常感谢。 问题答案: 基本上,表上的索引的作用类似于书中的索引(这就是名称的来源): 假设您有一本关于数据库的书,并且想要查找有关存储的信息。没有索引(假设没有其他帮助,例如目录),则必须逐个浏览页面,直到找到主题(即)为止。

  • 问题内容: 我最近问了一个有关“自我加入”的问题,得到了一个很好的答案。 该查询用于查找事件1之后1天的事件2的ID,开始日期和价格。 该代码工作正常。 但是我不知道如何。 有人可以尽可能详尽地解释一下-查询的不同部分是什么以及它们做什么? 非常感谢您的帮助,无论出于什么原因,我都很难解决这个问题。 问题答案: 我试图理解的方式是在第一块上写出两个列表,分别标记为event1和一个event2。然

  • 我试图了解mysql查询在GROUP BY和不使用GROUP BY的情况下是如何工作的。 假设我有一个FILM_ACTORS表,其中每个ACTOR_ID都有一个相应的film_id。于是同一个演员参演了N部不同的电影。 我想选出参与20部电影的演员: 这个查询起作用,并返回参与20部电影的actor_id。但如果我只是: 为什么该查询仅在我将其等于film_actor表(5463)的大小时才返回值

  • 问题内容: 我刚刚使用MySQL查询浏览器创建了一个新表,并注意到在“自动增量列”下有一个勾号。这是如何运作的? 以编程方式添加到数据库时,是否仅添加一个数字,然后数据库会自动将该数字递增? 每次有新用户在我的网站上注册时,我都希望他们的客户ID(仅整数)自动递增,因此我不必尝试随机生成一个唯一的数字。 可以简单地完成吗? 谢谢! 问题答案: 以编程方式添加到数据库时,是否仅添加一个数字,然后数据