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
조항 :
- https://docs.oracle.com/en/database/oracle/oracle-database/19/sqlrf/SELECT.html#GUID-CFA006CA-6FF1-4972-821E-6996142A51C6
- https://docs.oracle.com/en/database/oracle/oracle-database/19/sqlrf/SELECT.html#GUID-CFA006CA-6FF1-4972-821E-6996142A51C6
예를 들면 :
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
)
);