我使用以下查询在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和总数之间。的行。然后,我用那个没有。作为偏移量来获取该随机计数旁边的行。
答案 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),然后在该字段上执行上述查询。