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

Eug*_*ene 27 mysql random select

我一直在研究和测试如何在MySQL中进行快速随机选择.在这个过程中,我遇到了一些意想不到的结果,现在我不完全确定我知道ORDER BY RAND()是如何工作的.

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

SELECT * FROM Table T JOIN (SELECT CEIL(MAX(ID)*RAND()) AS ID FROM Table) AS x ON T.ID >= x.ID LIMIT 1;
Run Code Online (Sandbox Code Playgroud)

虽然常见的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*/
Run Code Online (Sandbox Code Playgroud)

我有点期待看到所有三个查询大致相同的时间,因为我总是在单个列上排序.但出于某种原因,这并没有发生.如果您对此有任何想法,请告诉我.我有一个项目,我需要快速ORDER BY RAND(),我个人更喜欢使用

SELECT id FROM table ORDER BY RAND() LIMIT 1;
SELECT * FROM table WHERE id=ID_FROM_PREVIOUS_QUERY LIMIT 1;
Run Code Online (Sandbox Code Playgroud)

其中,是的,比Jay的方法慢,但它更小,更容易理解.我的查询相当大,有几个JOIN和WHERE子句,虽然Jay的方法仍然有效,但查询变得非常庞大和复杂,因为我需要在JOINed(在他的查询中称为x)子请求中使用所有JOIN和WHERE.

谢谢你的时间!

Tor*_*amo 14

虽然没有"rand()快速订单"这样的东西,但是针对您的具体任务有一种解决方法.

为了得到任何一个随机的行,你可以像这样的德国博客做:http://www.roberthartung.de/mysql-order-by-rand-a-case-study-of-alternatives/(我看不到热门链接.如果有人看到,请随时编辑链接.)

该文本是德语,但SQL代码有点在页面下方和大白框中,因此不难看出.

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

这样做的缺点是,如果你删除很多行,并且存在巨大的差距,那么它很可能会错过很多次,从而使它失效.

更新:不同的执行时间

SELECT*FROM表ORDER BY RAND()LIMIT 1;/30-40秒 /

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

SELECT id,username FROM table ORDER BY RAND()LIMIT 1;/90秒 /

我有点期待看到所有三个查询大致相同的时间,因为我总是在单个列上排序.但出于某种原因,这并没有发生.如果您对此有任何想法,请告诉我.

它可能与索引有关.id索引和快速访问,而添加username到结果,意味着它需要从每一行读取并将其放入内存表.随着*它也有阅读一切入内存,但它并不需要跳跃的数据文件,这意味着没有时间失去了寻找.

仅当存在可变长度列(varchar/text)时才会产生差异,这意味着它必须检查长度,然后跳过该长度,而不是仅跳过每行之间的设置长度(或0).