代码之家  ›  专栏  ›  技术社区  ›  Chris Sobolewski

不使用rand()从mysql数据库返回随机行

  •  3
  • Chris Sobolewski  · 技术社区  · 14 年前

    WHERE id = rand() 当我的数据库变大时会导致性能问题。我看到的所有解决方案都是针对选择一个随机记录。我想要倍数。

    有没有人知道一种有效的方法来处理大型数据库?

    编辑:

    进一步编辑和测试:

    我使用MyISAM在一个新数据库上创建了一个相当简单的表。我给了这3个字段: autokey (无符号自动编号键) bigdata (一大团)和 somemore (中等智力)。

    Query 1: select * from test order by rand() limit 15

     Query 2: select * 
              from 
          test 
              join 
          (select round(rand()*(select max(autokey) from test)) as val from test limit 15)                                           as rnd
          on 
              rnd.val=test.autokey;`
    

    (我尝试了select和select distinct两种方法,但没有明显的区别)

    Query 3 (I only ran this on the second test):
    SELECT  *
        FROM    (
        SELECT  @cnt := COUNT(*) + 1,
                @lim := 10
        FROM    test
        ) vars
        STRAIGHT_JOIN
        (
        SELECT  r.*,
                @lim := @lim - 1
        FROM    test r
        WHERE   (@cnt := @cnt - 1)
                AND RAND(20090301) < @lim / @cnt
        ) i
    
    ROWS:            QUERY 1:               QUERY 2:         QUERY 3:
    2,060,922          2.977s                 0.002s            N/A
    
    3,043,406          5.334s                 0.001s            1.260     
    

    我想做更多的行,这样我就可以看到query3是如何伸缩的,但是现在, .

    在我结束测试并声明答案之前,当我设置了所有数据和测试环境时, 有人能推荐进一步的测试吗?

    5 回复  |  直到 14 年前
        1
  •  5
  •   Nordic Mainframe    14 年前

    尝试:

    select * from table order by rand() limit 15
    

    另一种(可能更有效的方法)是针对一组随机值进行连接。如果表中有一些连续的整数键,这应该可以工作。下面是我在这方面的做法 博士后 (我的MySQL有点生锈)

    select * from table join 
       (select (random()*maxid)::integer as val from generate_series(1,15)) as rnd
       on rand.val=table.id;
    

    其中maxid是最高的 id 在里面 table 身份证件

    更新 :

    在MySQL中似乎没有generate\ u series这样的东西。是我的错。实际上我们不需要它:

    select * 
    from 
     table 
    join 
     -- this just returns 15 random numbers. 
     -- I need `table` here only to produce rows for rand()
     (select round(rand()*(select max(id) from table)) as val from table limit 15) as rnd
    on 
     rnd.val=table.id;
    

    另外,如果我不想返回重复项,我可以在随机生成器表达式中使用(select distinct[…])。

        2
  •  2
  •   Community holdenweb    7 年前

    更新 :在中查看接受的答案 this question . 它是纯mySQL,甚至处理均匀分布。

    问题在于 id = rand() 或者在PHP中任何类似的东西都是,您不能确定那个特定的ID是否仍然存在。因此,你需要与 LIMIT ,对于大量数据来说,这可能会变得很慢。

    作为另一种选择,您可以尝试在PHP中使用循环。

    循环的作用是

    • 使用创建一个随机整数 rand() ,范围介于 0 以及数据库中的记录数

    • 查询数据库是否存在具有该ID的记录

    • 如果存在,则将数字添加到数组中

    • 如果没有,请返回步骤1

    • 当随机数数组包含所需数量的元素时结束循环

    可以 比…快 LIMIT rand() 在某些情况下。

    这个 方法,正如@Luther所概述的,无疑是最简单的代码方式。

        3
  •  0
  •   johnjoejohnjoe    14 年前

    您可以使用所有结果或有限的结果进行查询,然后使用mysqli\u fetch\u all后跟:

    shuffle($a);
    $a = array_slice($a, 0, 15);
    
        4
  •  0
  •   Gene Vincent    14 年前

    对于大型数据集

    select * from table order by rand() limit 15
    

    可能会耗费大量时间和内存。

    如果你的数据记录碰巧被编号了,你可以把索引放在编号栏上,然后做一个

    select * from table where no >= rand() limit 15
    

    select * from table where no >= $rand and no <= $rand+15
    

        5
  •  0
  •   tc.    14 年前

    假设MySQL支持嵌套查询,并且主键上的操作很快,我会尝试以下方法

    select * from table where id in (select id from table order by rand() limit 15)