如何从oracle数据库中随机获取记录?


82

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

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

Answers:


111
SELECT *
FROM   (
    SELECT *
    FROM   table
    ORDER BY DBMS_RANDOM.RANDOM)
WHERE  rownum < 21;

1
击败我。但是,这只会从表中选择前20行,并对它们进行随机排序。
Nishant Sharma 2012年

10
您必须意识到,这在大型表上是一项非常繁重的操作,因为它将首先为EACH行分配一个随机数,然后对该值进行排序,然后从中获取一些记录。
Roeland Van Heddegem 2015年

11
@NishantSharma,行是随机的,然后是有限的-您的评论不正确。
SimonMᶜKenzie17年

5
这种方法非常慢
Evan Kroske

1
@JonBetts,我认为示例速度更快,资源效率更高:stackoverflow.com/a/9920431/156787
Evan Kroske,

50

不能保证SAMPLE()会准确地为您提供20行,但可能是合适的(对于大型表,它的性能可能比完全查询+按随机排序好得多):

SELECT *
FROM   table SAMPLE(20);

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


1
样本速度很快,但看起来不是很随机。倾向于表顶部/开头的记录。
craigrs84 2014年

1
如果您在查询通过整个表之前停止查询,就会发生这种情况。
Jeffrey Kemp 2014年

2
抱歉,我犯了一个错误,您的帖子很好,结果平均分配。当您将“ where rownum <= 20”与sample(20)一起添加时,数据开始变得随机性降低。
craigrs84

13
SELECT * FROM table SAMPLE(10) WHERE ROWNUM <= 20;

由于不需要对表进行排序,因此效率更高。


7
在20行之后停止采样将导致非随机结果(在表中较早发现的行返回的频率将比在后面更频繁)。另外,不能保证返回20行。
杰弗里·肯普

10
SELECT column FROM
( SELECT column, dbms_random.value FROM table ORDER BY 2 )
where rownum <= 20;

4

要随机选择20行,我认为最好选择随机排列的行并选择该行的前20行。

就像是:

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

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


3

总之,介绍了两种方法

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

第一种方法在“ CORRECTNESS”中具有优势,这意味着如果结果确实存在,您将永远不会失败;而第二种方法,即使它的情况满足查询条件,您也不会获得任何结果,因为采样期间信息会减少。

第二种方法在'EFFICIENT'中具有优势,这意味着您将更快地获得结果并减轻数据库的负担。DBA给我警告,我的查询使用第一种方法会给数据库带来负载

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


1

在大型表的情况下,按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
      )
);

0

以下是从每个组中随机抽取样本的方法:

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;

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


By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.