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

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

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



답변

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


답변

SAMPLE () 은 정확히 20 개의 행을 제공 한다고 보장 되지는 않지만 적합 할 수 있습니다 (큰 테이블의 경우 전체 쿼리 + 무작위 정렬보다 훨씬 더 나은 성능을 발휘할 수 있음).

SELECT *
FROM   table SAMPLE(20);

참고 : 20여기는 원하는 행 수가 아닌 대략적인 백분율입니다. 이 경우 100 개의 행이 있으므로 약 20 개의 행을 얻으려면 20 % 샘플을 요청합니다.


답변

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

테이블을 정렬 할 필요가 없기 때문에 더 효율적입니다.


답변

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


답변

20 개의 행을 무작위로 선택하려면 무작위로 정렬 된 많은 행을 선택하고 해당 세트의 처음 20 개 행을 선택하는 것이 좋습니다.

다음과 같은 것 :

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

대부분의 데이터를 버리기 위해 큰 데이터 청크를 선택하지 않도록 작은 테이블에 가장 적합합니다.


답변

요약하면 두 가지 방법이 도입되었습니다.

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

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

두 번째 방법은 ‘효율적’이라는 장점이 있습니다. 즉, 결과를 더 빨리 얻고 데이터베이스에 가벼운 부하를 줄 수 있습니다. DBA로부터 첫 번째 방법을 사용한 쿼리가 데이터베이스에 부하를 준다는 경고를 받았습니다.

관심에 따라 두 가지 방법 중 하나를 선택할 수 있습니다!


답변

거대한 테이블의 경우 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
      )
);