Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/84.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
mysql中从大表中快速选择随机行_Mysql_Sql_Select_Random - Fatal编程技术网

mysql中从大表中快速选择随机行

mysql中从大表中快速选择随机行,mysql,sql,select,random,Mysql,Sql,Select,Random,从大型mysql表中选择随机行的快速方法是什么 我从事php工作,但我对任何解决方案都感兴趣,即使它是用另一种语言编写的。也许您可以做如下操作: SELECT * FROM table WHERE id= (FLOOR(RAND() * (SELECT COUNT(*) FROM table) ) ); 这是假设您的ID号都是连续的,没有间隔。在每行中添加一列,其中包含计算出的随机值,并在排序子句中使用该列,在选择时限制为一个结

从大型mysql表中选择随机行的快速方法是什么


我从事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
?>