【问题标题】:How to get records randomly from the oracle database?如何从oracle数据库中随机获取记录?
【发布时间】:2012-04-09 17:41:34
【问题描述】:

我需要从 Oracle 数据库中随机选择行。

例如:假设一个有 100 行的表,我如何从整个 100 行中随机返回 20 条记录。

【问题讨论】:

    标签: oracle select random


    【解决方案1】:
    SELECT *
    FROM   (
        SELECT *
        FROM   table
        ORDER BY DBMS_RANDOM.RANDOM)
    WHERE  rownum < 21;
    

    【讨论】:

    • 打败我。但是,这只会从表中选择前 20 行并随机排序。
    • 你必须知道,这对大表来说是一个非常繁重的操作,因为它会首先为每一行分配一个随机数,然后对这个值进行排序,然后从中取出一些记录。
    • @NishantSharma,行是随机的,然后有限 - 你的评论不正确。
    • 这种方法很慢
    • @JonBetts,我认为该示例更快,资源效率更高:stackoverflow.com/a/9920431/156787
    【解决方案2】:

    SAMPLE() 不能保证准确地为您提供 20 行,但可能是合适的(并且可能比完整查询 + 大表随机排序的性能要好得多):

    SELECT *
    FROM   table SAMPLE(20);
    

    注意:这里的20 是一个大概的百分比,而不是所需的行数。在这种情况下,由于您有 100 行,因此要获得大约 20 行,您需要 20% 的样本。

    【讨论】:

    • 样本速度很快,但似乎不是很随机。靠近表格顶部/开头的记录往往受到青睐。
    • 如果您在查询通过整个表之前停止查询,就会发生这种情况。
    • 对不起,我犯了一个错误,你的帖子很好,结果是平均分布的。当您结合 sample(20) 添加“where rownum
    【解决方案3】:
    SELECT * FROM table SAMPLE(10) WHERE ROWNUM <= 20;
    

    这样更高效,因为它不需要对表格进行排序。

    【讨论】:

    • 在 20 行后停止样本将导致非随机结果(在表中较早找到的行将比后面的行更频繁地返回)。此外,这不能保证返回 20 行。
    【解决方案4】:
    SELECT column FROM
    ( SELECT column, dbms_random.value FROM table ORDER BY 2 )
    where rownum <= 20;
    

    【讨论】:

      【解决方案5】:

      要随机选择 20 行,我认为您最好选择其中随机排序的很多行并选择该集合的前 20 行。

      类似:

      Select *
        from (select *
                from table
               order by dbms_random.value) -- you can also use DBMS_RANDOM.RANDOM
       where rownum < 21;
      

      最好用于小表,以避免选择大块数据而丢弃大部分数据。

      【讨论】:

        【解决方案6】:

        总结一下,介绍了两种方式

        1) using order by DBMS_RANDOM.VALUE clause
        2) using sample([%]) function
        

        第一种方式在 'CORRECTNESS' 中具有优势,这意味着如果结果确实存在,您将永远不会失败,而在第二种方式中,即使有满足查询条件的案例,您也可能得不到结果,因为在采样期间信息减少了.

        第二种方式在“高效”方面具有优势,这意味着您将更快地获得结果并减轻数据库的负载。 DBA 向我发出警告,我使用第一种方式的查询会给数据库带来负载

        您可以根据自己的兴趣选择两种方式中的一种!

        【讨论】:

          【解决方案7】:

          在大表的情况下,按 dbms_random.value 排序的标准方法无效,因为您需要扫描整个表,而 dbms_random.value 是一个非常慢的函数并且需要上下文切换。对于这种情况,还有 3 种额外的方法:


          1:使用sample子句:

          例如:

          select *
          from s1 sample block(1)
          order by dbms_random.value
          fetch first 1 rows only
          

          即获取所有块的 1%,然后将它们随机排序并仅返回 1 行。


          2:如果你在正态分布的列上有一个索引/主键,你可以得到最小值和最大值,在这个范围内得到随机值,并得到第一行的值更大或等于随机生成的值。

          例子:

          --big table with 1 mln rows with primary key on ID with normal distribution:
          Create table s1(id primary key,padding) as 
             select level, rpad('x',100,'x')
             from dual 
             connect by level<=1e6;
          
          select *
          from s1 
          where id>=(select 
                        dbms_random.value(
                           (select min(id) from s1),
                           (select max(id) from s1) 
                        )
                     from dual)
          order by id
          fetch first 1 rows only;
          

          3:获取随机表块,生成rowid并通过该rowid从表中获取行

          select * 
          from s1
          where rowid = (
             select
                DBMS_ROWID.ROWID_CREATE (
                   1, 
                   objd,
                   file#,
                   block#,
                   1) 
             from    
                (
                select/*+ rule */ file#,block#,objd
                from v$bh b
                where b.objd in (select o.data_object_id from user_objects o where object_name='S1' /* table_name */)
                order by dbms_random.value
                fetch first 1 rows only
                )
          );
          

          【讨论】:

            【解决方案8】:

            以下是如何从每组中随机抽取一个样本:

            SELECT GROUPING_COLUMN, 
                   MIN (COLUMN_NAME) KEEP (DENSE_RANK FIRST ORDER BY DBMS_RANDOM.VALUE) 
                     AS RANDOM_SAMPLE
            FROM TABLE_NAME
            GROUP BY GROUPING_COLUMN
            ORDER BY GROUPING_COLUMN;
            

            我不确定它的效率如何,但是如果您有很多类别和子类别,这似乎可以很好地完成工作。

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2012-04-13
              • 2018-07-20
              • 2017-10-05
              • 2011-01-27
              • 2011-04-07
              • 1970-01-01
              • 1970-01-01
              • 2019-03-25
              相关资源
              最近更新 更多