优化我的自定义RAND()查询

时间:2015-10-12 12:45:46

标签: mysql sql performance

我使用以下查询在MySql中获取随机行。并且,我认为它比ORDER BY RAND()快得多,因为它只是在随机计数行之后返回一行,并且不需要任何行排序。

SELECT COUNT(ID) FROM TABLE_NAME

!-- GENERATE A RANDOM NUMBER BETWEEN 0 and COUNT(ID)-1 --!

SELECT x FROM TABLE_NAME LIMIT RANDOM_NUMBER,1

但是,我需要知道,无论如何,我可以更多地优化它,并且有更快的方法。

我也很高兴知道我是否可以合并2个查询,因为LIMIT不支持此类子查询(据我所知)

编辑 - 我的查询工作方式不是随机生成任何ID。但相反,它会生成随机数。介于0和总数之间。的行。然后,我用那个没有。作为偏移量来获取该随机计数旁边的行。

4 个答案:

答案 0 :(得分:1)

我认为您想要的查询是:

select x.*
from tablename x
where x.id >= random_number
order by x.id
limit 1;

这应该使用x.id上的索引并且应该非常快。您可以将它们组合为:

select x.*
from tablename x cross join
     (select cast(max(id) * rand() as int) as random_number from tablename
     ) c
where x.id >= random_number
order by x.id
limit 1;

请注意,您应该使用max(id)而不是count(),因为ID中可能存在空白。子查询还应该使用id上的索引。

编辑:

我不会对上述解决方案采取防御措施。它返回一个随机id,但id不是均匀分布的。

无论如何,我首选的方法是:

select x.*
from tablename x cross join
     (select count(*) as cnt from x) cnt
where rand() < 100 / cnt
order by rand()
limit 1;

高度,极不可能不会得到where条件的行(这是可能的,但极不可能)。最终的order by rand()只处理100行,所以它应该非常快。

答案 1 :(得分:1)

编辑:我的答案假设MySql&lt; 5.5.6,你无法将变量传递给LIMIT和OFFSET。否则,OP的方法是最好的。

最可靠的解决方案imo是对结果进行排名以消除差距。我的解决方案可能不是最优的,因为我不熟悉MySQL,但逻辑有效(或在我的SQLFiddle中工作)。

SET @total = 0;

SELECT @total := COUNT(1) FROM test;

SET @random=FLOOR(RAND()*@total)+1;
SET @rank=0;

SELECT * from 
    (SELECT @rank:=@rank+1 as rank, id, name
    FROM test
    order by id) derived_table
where rank = @random;

如果你在一个大规模的查询中使用它,我不确定这个结构会如何变老,但只要你在几百行内它就应该是即时的。

基本上,你生成一个随机的行号(这是最有可能进行优化的地方之一):

SET @total = 0;
SELECT @total := COUNT(1) FROM test;
SET @random=FLOOR(RAND()*@total)+1;

然后,您对所有行进行排名以消除差距:

SELECT @rank:=@rank+1 as rank, id, name
FROM test
order by id

然后,您选择随机选择的行:

SELECT * from 
    (ranked derived table) derived_table
where rank = @random;

答案 2 :(得分:0)

http://mysql.rjweb.org/doc.php/random中有5种技巧。他们都不必看整张桌子。

你有AUTO_INCREMENT吗?有没有差距?其他问题需要回答才能知道该链接中哪种技术甚至适用。

答案 3 :(得分:-1)

尝试缓存第一个查询的结果并在第二个查询中使用。在同一查询中使用两者对系统来说非常沉重。

对于第二个查询,请尝试以下操作:

SELECT x FROM TABLE_NAME WHERE ID = RANDOM_NUMBER

上述查询比你的查询要快得多(假设ID被编入索引)

当然,上述查询假定您使用的是顺序ID(无间隙)。如果存在间隙,则需要创建另一个连续字段(可能称之为ID2),然后在该字段上执行上述查询。