mysql中从大表中快速选择随机行
从大型mysql表中选择随机行的快速方法是什么mysql中从大表中快速选择随机行,mysql,sql,select,random,Mysql,Sql,Select,Random,从大型mysql表中选择随机行的快速方法是什么 我从事php工作,但我对任何解决方案都感兴趣,即使它是用另一种语言编写的。也许您可以做如下操作: SELECT * FROM table WHERE id= (FLOOR(RAND() * (SELECT COUNT(*) FROM table) ) ); 这是假设您的ID号都是连续的,没有间隔。在每行中添加一列,其中包含计算出的随机值,并在排序子句中使用该列,在选择时限制为一个结
我从事php工作,但我对任何解决方案都感兴趣,即使它是用另一种语言编写的。也许您可以做如下操作:
SELECT * FROM table
WHERE id=
(FLOOR(RAND() *
(SELECT COUNT(*) FROM table)
)
);
这是假设您的ID号都是连续的,没有间隔。在每行中添加一列,其中包含计算出的随机值,并在排序子句中使用该列,在选择时限制为一个结果。这比使用
orderbyrandom()
导致的表扫描更快
更新:在检索时发出SELECT
语句之前,您仍然需要计算一些随机值,例如
SELECT * FROM `foo` WHERE `foo_rand` >= {some random value} LIMIT 1
经典的“按RAND()限制1从表顺序中选择id”实际上是可以的
请参阅MySQL手册的以下摘录:
如果将“限制行计数”与“排序依据”一起使用,MySQL将在找到排序结果的第一行计数行后立即结束排序,而不是对整个结果进行排序 一个简单但缓慢的方法是(适合小桌子)
获取所有id,从中随机选取一个,然后检索整行 如果你知道id是连续的,没有孔,你可以抓取最大值并计算一个随机id 如果到处都有洞,但大多是连续的值,并且您不关心稍微倾斜的随机性,请获取最大值,计算id,然后选择id等于或高于您计算的id的第一行。造成这种倾斜的原因是,跟随这些洞的id比跟随另一个id的id有更高的被拾取的机会 如果你随机点菜,你的手上会有一个可怕的表格扫描,快速这个词不适用于这种解决方案
不要这样做,也不应该按GUID排序,它也有同样的问题。有了订单,您将执行完整的扫描表。 最好是执行select count(*),然后在伪代码中获得介于0和最后一个注册表之间的随机行=rownum:
sql "select id from table"
store result in list
n = random(size of list)
sql "select * from table where id=" + list[n]
这假设
id
是唯一的(主键)。我知道必须有一种方法可以在单个查询中以快速的方式完成。这是:
一种无需外部代码参与的快速方式,值得称赞
这是一个运行相当快的解决方案,它可以获得更好的随机分布,而不依赖于id值是连续的或从1开始
SET @r := (SELECT ROUND(RAND() * (SELECT COUNT(*) FROM mytable)));
SET @sql := CONCAT('SELECT * FROM mytable LIMIT ', @r, ', 1');
PREPARE stmt1 FROM @sql;
EXECUTE stmt1;
MediaWiki使用了一个有趣的技巧(用于Wikipedia的特殊功能:Random):包含文章的表有一个带有随机数的额外列(在创建文章时生成)。要获取随机文章,请生成一个随机数,并获取随机数列中具有下一个较大或较小(不记得是哪个)值的文章。有了索引,这可能会非常快。(MediaWiki是用PHP编写的,是为MySQL开发的。) 如果生成的数字分布不均,这种方法可能会导致问题;IIRC,这已在MediaWiki上修复,因此,如果您决定以这种方式执行此操作,您应该查看代码以了解当前的执行情况(可能他们会定期重新生成随机数列)。快速脏方法: 对于MyISAM表,第一个查询的复杂性是O(1) 第二个查询伴随着表完整扫描。复杂性=O(n) 肮脏和快速的方法: 为此,请单独保留一张桌子。每次插入到原始表时,也应将相同的行插入到此表。假设:没有删除
CREATE TABLE Aux(
MyPK INT AUTO_INCREMENT,
PrimaryKey INT
);
SET @MaxPK = (SELECT MAX(MyPK) FROM Aux);
SET @RandPK = CAST(RANDOM() * @MaxPK, INT)
SET @PrimaryKey = (SELECT PrimaryKey FROM Aux WHERE MyPK = @RandPK);
如果允许删除
SET @delta = CAST(@RandPK/10, INT);
SET @PrimaryKey = (SELECT PrimaryKey
FROM Aux
WHERE MyPK BETWEEN @RandPK - @delta AND @RandPK + @delta
LIMIT 1);
总体复杂度为O(1)。我对SQL有点陌生,但是在PHP中生成一个随机数并使用
SELECT * FROM the_table WHERE primary_key >= $randNr
这并不能解决桌子上有洞的问题
但拉塞夫斯克的建议有一个转折点:
SELECT primary_key FROM the_table
在PHP中使用mysql_num_rows()根据上述结果创建一个随机数:
SELECT * FROM the_table WHERE primary_key = rand_number
另一方面,请注意从_表中选择*的速度有多慢:基于
mysql\u num\u rows()
创建一个随机数,然后将数据指针移动到该点mysql\u data\u seek()
。在有一百万行的大桌子上,这会有多慢?看看Jan Kneschke的文章,或者他们讨论的是同一个问题。因此,答案也涵盖了各种选项,并根据您的需要提供了一些好的建议。Jan回顾了所有不同的选项以及每个选项的性能特征。最后,他提出了以下在MySQL select中执行此操作的最佳方法:
SELECT name
FROM random AS r1 JOIN
(SELECT (RAND() *
(SELECT MAX(id)
FROM random)) AS id)
AS r2
WHERE r1.id >= r2.id
ORDER BY r1.id ASC
LIMIT 1;
嗯,
-Dipin为了从给定的表中选择多个随机行(比如“单词”),我们的团队想出了以下妙招:
SELECT * FROM
`words` AS r1 JOIN
(SELECT MAX(`WordID`) as wid_c FROM `words`) as tmp1
WHERE r1.WordID >= (SELECT (RAND() * tmp1.wid_c) AS id) LIMIT n
还有另一种方法可以仅使用查询而不使用order by rand()生成随机行。 它涉及用户定义的变量。
请参见如果不删除此表中的行,最有效的方法是: (如果您知道mininum id,请跳过它)
为了从表中查找随机行,不要使用order BY RAND(),因为它强制MySQL进行完整的文件排序,然后才检索所需的限制行数。为了避免这种完整的文件排序,请仅在where子句中使用RAND()函数。它将在达到所需行数时停止。 看见
我遇到了ID不连续的问题。我想到了这个
SELECT * FROM products WHERE RAND()<=(5/(SELECT COUNT(*) FROM products)) LIMIT 1
SELECT*FROM products WHERE RAND()SELECT DISTINCT*FROM your table WHERE 4=4 LIMIT 1代码>我在这里看到了很多解决方案。一个或两个看起来不错,但其他解决方案有一些限制。但以下解决方案适用于所有情况
select a.* from random_data a, (select max(id)*rand() randid from random_data) b
where a.id >= b.randid limit 1;
这里,id,不需要按顺序排列。它可以是任何主键/唯一/自动增量列。请参见以下内容
谢谢
齐卢尔
-使用下面的查询获取随机行
SELECT user_firstname ,
COUNT(DISTINCT usr_fk_id) cnt
FROM userdetails
GROUP BY usr_fk_id
ORDER BY cnt ASC
LIMIT 1
在我的例子中,我的表有一个id作为主键,自动递增,没有间隙,所以我可以使用<
SELECT MIN(id) AS minId, MAX(id) AS maxId FROM table WHERE 1
$randId=mt_rand((int)$row['minId'], (int)$row['maxId']);
SELECT id,name,... FROM table WHERE id=$randId LIMIT 1
SELECT * FROM products WHERE RAND()<=(5/(SELECT COUNT(*) FROM products)) LIMIT 1
SELECT * FROM products WHERE RAND()<=(100/(SELECT COUNT(*) FROM pt_products)) AND discount<.2 LIMIT 1
select a.* from random_data a, (select max(id)*rand() randid from random_data) b
where a.id >= b.randid limit 1;
SELECT user_firstname ,
COUNT(DISTINCT usr_fk_id) cnt
FROM userdetails
GROUP BY usr_fk_id
ORDER BY cnt ASC
LIMIT 1
logTime();
query("SELECT COUNT(id) FROM tbl");
logTime();
query("SELECT MAX(id) FROM tbl");
logTime();
query("SELECT id FROM tbl ORDER BY id DESC LIMIT 1");
logTime();
SELECT FLOOR(RAND() * (
SELECT id FROM tbl ORDER BY id DESC LIMIT 1
)) n FROM tbl LIMIT 1
...
SELECT * FROM tbl WHERE id = $result;
SELECT * FROM myTable WHERE RAND()<(SELECT ((30/COUNT(*))*10) FROM myTable) ORDER BY RAND() LIMIT 30;
<?
$sqlConnect = mysqli_connect('localhost','username','password','database');
function rando($data,$find,$max = '0'){
global $sqlConnect; // Set as mysqli connection variable, fetches variable outside of function set as GLOBAL
if($data == 's1'){
$query = mysqli_query($sqlConnect, "SELECT * FROM `yourtable` ORDER BY `id` DESC LIMIT {$find},1");
$fetched_data = mysqli_fetch_assoc($query);
if(mysqli_num_rows($fetched_data>0){
return $fetch_$data;
}else{
rando('','',$max); // Start Over the results returned nothing
}
}else{
if($max != '0'){
$irand = rand(0,$max);
rando('s1',$irand,$max); // Start rando with new random ID to fetch
}else{
$query = mysqli_query($sqlConnect, "SELECT `id` FROM `yourtable` ORDER BY `id` DESC LIMIT 0,1");
$fetched_data = mysqli_fetch_assoc($query);
$max = $fetched_data['id'];
$irand = rand(1,$max);
rando('s1',$irand,$max); // Runs rando against the random ID we have selected if data exist will return
}
}
}
$your_data = rando(); // Returns listing data for a random entry as a ASSOC ARRAY
?>