Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/mysql/55.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 - Fatal编程技术网

Mysql 在不扫描整个数据库的情况下获取随机帖子

Mysql 在不扫描整个数据库的情况下获取随机帖子,mysql,Mysql,如何在不扫描整个数据库的情况下获得随机帖子 我知道,如果使用MySQLorderbyrand()它将扫描整个数据库 如果有任何其他方法可以在不扫描整个数据库的情况下执行此操作。许多人似乎相信,ORDER BY RAND()在某种程度上可以在不扫描整个表的情况下生成结果 事实并非如此。事实上,它可能比按列值排序慢,因为MySQL必须为每一行调用RAND()函数 为了演示,我制作了一个包含50万MD5哈希的简单表: mysql> select count(*) from delete_me;

如何在不扫描整个数据库的情况下获得随机帖子

我知道,如果使用MySQL
orderbyrand()
它将扫描整个数据库


如果有任何其他方法可以在不扫描整个数据库的情况下执行此操作。

许多人似乎相信,
ORDER BY RAND()
在某种程度上可以在不扫描整个表的情况下生成结果

事实并非如此。事实上,它可能比按列值排序慢,因为MySQL必须为每一行调用RAND()函数

为了演示,我制作了一个包含50万MD5哈希的简单表:

mysql> select count(*) from delete_me;
+----------+
| count(*) |
+----------+
|   500000 |
+----------+
1 row in set (0.00 sec)

mysql> explain delete_me;
+-------+------------------+------+-----+---------+----------------+
| Field | Type             | Null | Key | Default | Extra          |
+-------+------------------+------+-----+---------+----------------+
| id    | int(10) unsigned | NO   | PRI | NULL    | auto_increment |
| txt   | text             | NO   |     | NULL    |                |
+-------+------------------+------+-----+---------+----------------+
2 rows in set (0.12 sec)

mysql> select * from delete_me limit 4;
+----+----------------------------------+
| id | txt                              |
+----+----------------------------------+
|  1 | 9b912c03d87991b71955a6cd4f81a299 |
|  2 | f1b7ddeb1c1a14265a620b8f2366a22e |
|  3 | 067b39538b767e2382e557386cba37d9 |
|  4 | 1a27619c1d2bb8fa583813fdd948e94c |
+----+----------------------------------+
4 rows in set (0.00 sec)
使用
ORDER BY RAND()
从该表中随机选择一行需要我的计算机1.95秒

mysql> select * from delete_me order by rand() limit 1;
+--------+----------------------------------+
| id     | txt                              |
+--------+----------------------------------+
| 446149 | b5f82dd78a171abe6f7bcd024bf662e8 |
+--------+----------------------------------+
1 row in set (1.95 sec)
但按升序排列文本字段只需0.8秒

mysql> select * from delete_me order by txt asc limit 1;
+-------+----------------------------------+
| id    | txt                              |
+-------+----------------------------------+
| 88583 | 00001e65c830f5b662ae710f11ae369f |
+-------+----------------------------------+
1 row in set (0.80 sec)
由于此表中的id值从1开始按顺序编号,因此我可以更快地选择一个随机行,如下所示:

mysql> select * from delete_me where id=floor(1+rand()*500000) limit 1;
+-------+----------------------------------+
| id    | txt                              |
+-------+----------------------------------+
| 37600 | 3b8aaaf88af68ca0c6eccff7e61e897a |
+-------+----------------------------------+
1 row in set (0.02 sec)

但在一般情况下,我建议在@deceze链接的页面中使用。

我对此类要求的建议是使用MD5哈希

  • 在DB表中添加一个字段CHAR(32),并为其创建和索引
  • 用MD5哈希值填充每个记录(可能是ID列中的值,也可能是任何旧的随机数,只要每个记录都不同,就不太重要)
  • 现在可以按如下方式查询表:

    SELECT * FROM myTable WHERE md5Col > MD5(NOW()) LIMIT 1
    
  • 这将为您提供一条随机记录,而无需扫描整个表。由于MD5值,该表具有随机排序顺序。MD5在这方面很好,因为它快速且随机分布

    注意事项:

    • 如果SELECT查询中的MD5导致哈希值大于表中的最后一条记录,则可能无法从查询中获得任何记录。如果发生这种情况,您总是可以使用新的哈希重新查询它
    • 在每个记录上有一个固定的MD5散列意味着这些记录的顺序是固定的。如果您一次只获取一条记录,那么这并不是一个真正的问题,但是如果您使用它来获取多组记录,那么可能会注意到这一点。如果需要,您当然可以通过在加载记录时重新对其进行灰化来更正此问题

    对使用主键值的
    @squamish ossifrage
    解决方案的一个微小修改-假设在具有数值的表中存在主键:

    SELECT *
    FROM delete_me
    WHERE id >= Round(  Rand() *
         ( SELECT Max( id ) FROM test ))
    LIMIT 1
    
    对于包含超过50000行的表,查询将在100毫秒内运行:

       mysql> SELECT  id, table_schema, table_name   
              FROM delete_me   
              WHERE id >= Round(  Rand() *         
                       ( SELECT Max( id ) FROM delete_me ))
              LIMIT 1;
        +-----+--------------------+------------+
        | id  | table_schema       | table_name |
        +-----+--------------------+------------+
        | 173 | information_schema | PLUGINS    |
        +-----+--------------------+------------+
        1 row in set (0.01 sec)
    

    使用
    ORDER BY RAND()LIMIT 1
    。@Joke仍然会对整个表进行排序,这正是OP不想要的。@如果他正在查找单行结果,则不会进行排序。@Joke它会首先对整个表进行排序,然后从中返回第一个结果!所有的
    orderby
    子句都会这样做,否则您将无法得到正确的结果。这是一项昂贵的手术,众所周知,这是一项昂贵的手术,也是手术医生提出这个问题的原因。@deceze可能是我错了,但我从以下参考文献中得出结论:1。正如你所指出的,你的帖子中提供的唯一答案在现实生活中是不适用的。2.为了演示,必须解释查询,而不是表。如果您可能需要至少使用两个查询,
    。。。限制n,1
    其中n≤ <代码>计数(*)似乎更直截了当。不过这是一个有趣的方法。