Rie*_*sio 368
一个伟大的岗位处理几个案例,从简单到间隙,到不均匀的差距.
http://jan.kneschke.de/projects/mysql/order-by-rand/
对于大多数一般情况,以下是您的操作方法:
SELECT name
FROM random AS r1 JOIN
(SELECT CEIL(RAND() *
(SELECT MAX(id)
FROM random)) AS id)
AS r2
WHERE r1.id >= r2.id
ORDER BY r1.id ASC
LIMIT 1
Run Code Online (Sandbox Code Playgroud)
这假设id的分布相等,并且id列表中可能存在间隙.有关更多高级示例,请参阅文章
Pre*_*bia 328
SELECT column FROM table
ORDER BY RAND()
LIMIT 10
Run Code Online (Sandbox Code Playgroud)
不是有效的解决方案,但有效
sni*_*ode 17
我使用缓慢的CPU获得快速查询(大约0.5秒),在400K寄存器MySQL数据库非缓存2Gb大小中选择10个随机行.在这里看到我的代码:在MySQL中快速选择随机行
<?php
$time= microtime_float();
$sql='SELECT COUNT(*) FROM pages';
$rquery= BD_Ejecutar($sql);
list($num_records)=mysql_fetch_row($rquery);
mysql_free_result($rquery);
$sql="SELECT id FROM pages WHERE RAND()*$num_records<20
ORDER BY RAND() LIMIT 0,10";
$rquery= BD_Ejecutar($sql);
while(list($id)=mysql_fetch_row($rquery)){
if($id_in) $id_in.=",$id";
else $id_in="$id";
}
mysql_free_result($rquery);
$sql="SELECT id,url FROM pages WHERE id IN($id_in)";
$rquery= BD_Ejecutar($sql);
while(list($id,$url)=mysql_fetch_row($rquery)){
logger("$id, $url",1);
}
mysql_free_result($rquery);
$time= microtime_float()-$time;
logger("num_records=$num_records",1);
logger("$id_in",1);
logger("Time elapsed: <b>$time segundos</b>",1);
?>
Run Code Online (Sandbox Code Playgroud)
Muh*_*eem 16
它非常简单和单行查询.
SELECT * FROM Table_Name ORDER BY RAND() LIMIT 0,10;
Run Code Online (Sandbox Code Playgroud)
Ali*_*Ali 16
具有出色性能的简单查询(适用于间隙):
SELECT * FROM tbl WHERE id IN
(SELECT id FROM (SELECT id FROM tbl ORDER BY RAND() LIMIT 10) t)
Run Code Online (Sandbox Code Playgroud)
使用了两个嵌套子查询,因为MySQL尚未在第一个中支持LIMIT.
这很快,因为排序阶段仅使用索引ID列.
对于加权版本:https://stackoverflow.com/a/41577458/893432
zlo*_*ctb 13
从书中:
使用偏移选择随机行
避免前面替代方案中发现的问题的另一种技术是计算数据集中的行并返回0和计数之间的随机数.然后在查询数据集时使用此数字作为偏移量
<?php
$rand = "SELECT ROUND(RAND() * (SELECT COUNT(*) FROM Bugs))";
$offset = $pdo->query($rand)->fetch(PDO::FETCH_ASSOC);
$sql = "SELECT * FROM Bugs LIMIT 1 OFFSET :offset";
$stmt = $pdo->prepare($sql);
$stmt->execute( $offset );
$rand_bug = $stmt->fetch();
Run Code Online (Sandbox Code Playgroud)
当您无法假设连续的键值时,请使用此解决方案,并且需要确保每行都有偶然的机会被选中.
好吧,如果您的密钥没有间隙并且它们都是数字,您可以计算随机数并选择这些线.但情况可能并非如此.
所以一个解决方案如下:
SELECT * FROM table WHERE key >= FLOOR(RAND()*MAX(id)) LIMIT 1
Run Code Online (Sandbox Code Playgroud)
这基本上可以确保您获得钥匙范围内的随机数,然后选择更好的下一个最佳值.你必须这样做10次.
但这并不是随机的,因为你的密钥很可能不会均匀分布.
这真的是一个很大的问题,并不容易解决满足所有要求,如果你真的想要10个随机行,MySQL的rand()是你能得到的最好的.
然而,有另一个解决方案是快速的,但在随机性方面也有一个折衷,但可能更适合你.在这里阅读:如何优化MySQL的ORDER BY RAND()函数?
问题是你需要它是多么随机.
你能解释一下吗,我可以给你一个很好的解决方案.
例如,我工作过的公司有一个解决方案,他们需要非常快速的绝对随机性.他们最终使用随机值预先填充数据库,然后再次选择降序并设置为不同的随机值.
如果您几乎没有更新,您也可以填充递增ID,这样您就没有间隙,只能在选择之前计算随机密钥...这取决于用例!
小智 7
如何从表中选择随机行:
从这里: 在MySQL中选择随机行
对"表扫描"的快速改进是使用索引来获取随机ID.
SELECT *
FROM random, (
SELECT id AS sid
FROM random
ORDER BY RAND( )
LIMIT 10
) tmp
WHERE random.id = tmp.sid;
Run Code Online (Sandbox Code Playgroud)
所有最佳答案都已发布(主要是引用链接http://jan.kneschke.de/projects/mysql/order-by-rand/的答案)。
我想指出另一种加速可能性——缓存。想想为什么需要获取随机行。也许您想在网站上显示一些随机帖子或随机广告。如果每秒获得 100 个请求,是否真的需要每个访问者都获得随机行?通常将这 X 个随机行缓存 1 秒(甚至 10 秒)是完全可以的。如果同一 1 秒内 100 个唯一访问者获得相同的随机帖子并不重要,因为下一秒另外 100 个访问者将获得不同的帖子集。
使用此缓存时,您还可以使用一些较慢的解决方案来获取随机数据,因为无论您的请求如何,每秒只会从 MySQL 获取一次数据。
我改进了@Riedsio 的答案。这是我能在具有间隙的大型均匀分布表上找到的最有效的查询(测试是从具有 > 2.6B 行的表中获取 1000 个随机行)。
(SELECT id FROM table INNER JOIN (SELECT FLOOR(RAND() * @max := (SELECT MAX(id) FROM table)) + 1 as rand) r on id > rand LIMIT 1) UNION
(SELECT id FROM table INNER JOIN (SELECT FLOOR(RAND() * @max) + 1 as rand) r on id > rand LIMIT 1) UNION
(SELECT id FROM table INNER JOIN (SELECT FLOOR(RAND() * @max) + 1 as rand) r on id > rand LIMIT 1) UNION
(SELECT id FROM table INNER JOIN (SELECT FLOOR(RAND() * @max) + 1 as rand) r on id > rand LIMIT 1) UNION
(SELECT id FROM table INNER JOIN (SELECT FLOOR(RAND() * @max) + 1 as rand) r on id > rand LIMIT 1) UNION
(SELECT id FROM table INNER JOIN (SELECT FLOOR(RAND() * @max) + 1 as rand) r on id > rand LIMIT 1) UNION
(SELECT id FROM table INNER JOIN (SELECT FLOOR(RAND() * @max) + 1 as rand) r on id > rand LIMIT 1) UNION
(SELECT id FROM table INNER JOIN (SELECT FLOOR(RAND() * @max) + 1 as rand) r on id > rand LIMIT 1) UNION
(SELECT id FROM table INNER JOIN (SELECT FLOOR(RAND() * @max) + 1 as rand) r on id > rand LIMIT 1) UNION
(SELECT id FROM table INNER JOIN (SELECT FLOOR(RAND() * @max) + 1 as rand) r on id > rand LIMIT 1)
Run Code Online (Sandbox Code Playgroud)
让我来解开到底发生了什么。
@max := (SELECT MAX(id) FROM table)
MAX(id)对于非常大的表,每次需要一行时都会有轻微的计算开销SELECT FLOOR(rand() * @max) + 1 as rand)
SELECT id FROM table INNER JOIN (...) on id > rand LIMIT 1
进行联合可以帮助您将所有内容放入 1 个查询中,这样您就可以避免执行多个查询。它还可以让您节省计算开销MAX(id)。根据您的应用程序,这可能很重要,也可能很重要。
请注意,这仅获取 id 并按随机顺序获取它们。如果您想做更高级的事情,我建议您这样做:
SELECT t.id, t.name -- etc, etc
FROM table t
INNER JOIN (
(SELECT id FROM table INNER JOIN (SELECT FLOOR(RAND() * @max := (SELECT MAX(id) FROM table)) + 1 as rand) r on id > rand LIMIT 1) UNION
(SELECT id FROM table INNER JOIN (SELECT FLOOR(RAND() * @max) + 1 as rand) r on id > rand LIMIT 1) UNION
(SELECT id FROM table INNER JOIN (SELECT FLOOR(RAND() * @max) + 1 as rand) r on id > rand LIMIT 1) UNION
(SELECT id FROM table INNER JOIN (SELECT FLOOR(RAND() * @max) + 1 as rand) r on id > rand LIMIT 1) UNION
(SELECT id FROM table INNER JOIN (SELECT FLOOR(RAND() * @max) + 1 as rand) r on id > rand LIMIT 1) UNION
(SELECT id FROM table INNER JOIN (SELECT FLOOR(RAND() * @max) + 1 as rand) r on id > rand LIMIT 1) UNION
(SELECT id FROM table INNER JOIN (SELECT FLOOR(RAND() * @max) + 1 as rand) r on id > rand LIMIT 1) UNION
(SELECT id FROM table INNER JOIN (SELECT FLOOR(RAND() * @max) + 1 as rand) r on id > rand LIMIT 1) UNION
(SELECT id FROM table INNER JOIN (SELECT FLOOR(RAND() * @max) + 1 as rand) r on id > rand LIMIT 1) UNION
(SELECT id FROM table INNER JOIN (SELECT FLOOR(RAND() * @max) + 1 as rand) r on id > rand LIMIT 1)
) x ON x.id = t.id
ORDER BY t.id
Run Code Online (Sandbox Code Playgroud)
我浏览了所有答案,我认为根本没有人提到这种可能性,我也不知道为什么。
如果您想要以较小的成本实现最大的简单性和速度,那么对我来说,针对数据库中的每一行存储一个随机数似乎是有意义的。只需创建一个额外的列 ,random_number并将其默认设置为RAND()。在此列上创建索引。
然后,当您想要检索行时,在代码(PHP、Perl 等)中生成一个随机数,并将其与列进行比较。
SELECT FROM tbl WHERE random_number >= :random LIMIT 1
Run Code Online (Sandbox Code Playgroud)
我想虽然对于单行来说它非常整洁,但对于像OP所要求的十行,你必须单独调用它十次(或者想出一个立即逃脱我的巧妙调整)
| 归档时间: |
|
| 查看次数: |
432101 次 |
| 最近记录: |