Oracle 데이터베이스에서 무작위로 레코드를 가져 오는 방법은 무엇입니까?


82

Oracle DB에서 임의로 행을 선택해야합니다.

예 : 100 개의 행이있는 테이블을 가정하면 전체 100 개 행에서 20 개의 레코드를 무작위로 반환 할 수 있습니다.

답변:


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

1
나를 이길. 그러나 이것은 테이블에서 처음 20 개 행만 선택하고 무작위로 정렬합니다.
Nishant Sharma

10
이 작업은 먼저 각 행에 임의의 숫자를 할당 한 다음이 값을 정렬 한 다음 여기에서 레코드를 가져 오므로 큰 테이블에서는 매우 무거운 작업입니다.
Roeland Van Heddegem

11
@NishantSharma, 행은, 무작위 다음 제한 - 귀하의 코멘트가 올바르지 않습니다.
Simon MᶜKenzie

5
이 방법은 매우 느립니다
에반 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-07-28

1
전체 테이블을 통과하기 전에 쿼리를 중지하면 발생합니다.
Jeffrey Kemp

2
실수로 죄송합니다. 귀하의 게시물은 괜찮으며 결과는 균등하게 배포됩니다. sample (20)과 함께 "where rownum <= 20"을 추가하면 데이터가 덜 무작위 적이되기 시작합니다.
craigrs84 2014-07-29

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

첫 번째 방법은 '정확성'이라는 장점이있어 실제로 존재하면 결과를 얻지 못함을 의미하고, 두 번째 방법은 샘플링 중에 정보가 줄어들 기 때문에 쿼리 조건을 만족하는 경우가 있어도 결과를 얻지 못할 수 있습니다.

두 번째 방법은 '효율적'이라는 장점이 있습니다. 즉, 결과를 더 빨리 얻고 데이터베이스에 가벼운 부하를 줄 수 있습니다. 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;

얼마나 효율적인지 잘 모르겠지만 카테고리와 하위 카테고리가 많으면이 작업을 잘 수행하는 것 같습니다.


당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.