개요
랜덤 Ton-N 쿼리를 사용하지 않아도 로우를 랜덤하게 조회할 수 있습니다.
테스트를 위해 아래와 같이 테이블을 생성하겠습니다. t1 테이블에는 10,000,000개의 행이 저장되어 있습니다.
-- 1
DROP TABLE t1 PURGE;
DROP TABLE t2 PURGE;
DROP TABLE t3 PURGE;
DROP TABLE t4 PURGE;
CREATE TABLE t1 (c1, c2) AS SELECT ROWNUM, LPAD ('X', 100, 'X') FROM XMLTABLE ('1 to 10000000');
CREATE TABLE t2 (c1 NUMBER, c2 VARCHAR2(100));
CREATE TABLE t3 (c1 NUMBER, c2 VARCHAR2(100));
CREATE TABLE t4 (c1 NUMBER, c2 VARCHAR2(100));
CREATE UNIQUE INDEX t1_u1 ON t1 (c1);
SAMPLE 절
아래 쿼리는 SAMPLE 절로 로우를 랜덤하게 조회합니다. 3개의 블록 I/O가 발생합니다.
-- 2
SELECT c1
FROM t1 SAMPLE (1)
WHERE ROWNUM = 1;
--------------------------------------------------------
| Id | Operation | Name | A-Rows | Buffers |
--------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 3 |
|* 1 | COUNT STOPKEY | | 1 | 3 |
| 2 | TABLE ACCESS SAMPLE| T1 | 1 | 3 |
--------------------------------------------------------
데이터 분포를 확인하기 위해 앞선 쿼리를 10,000번 수행한 결과를 t2 테이블에 저장하겠습니다. 수행에 7.58초가 소요됩니다.
-- 3
BEGIN
FOR i IN 1 .. 10000 LOOP
INSERT
INTO t2
SELECT *
FROM t1 SAMPLE (1)
WHERE ROWNUM = 1;
END LOOP;
COMMIT;
END;
/
경 과: 00:00:07.58
t2 테이블의 백분위 비율을 조회하면 대부분의 데이터가 1에서 100,000 사이에 분포되어 있음을 알 수 있습니다.
-- 4
SELECT CEIL (c1 / 100000) AS c1
, COUNT (*) AS cnt
FROM t2
GROUP BY CEIL (c1 / 100000)
ORDER BY c1;
C1 CNT
-- -----
1 10000
1개의 행이 선택되었습니다.
SAMPLE BLOCK 절
아래 쿼리는 SAMPLE BLOCK 절로 로우를 랜덤하게 조회합니다. 13개의 블록 I/O가 발생합니다.
-- 5
SELECT c1
FROM t1 SAMPLE BLOCK (1)
WHERE ROWNUM = 1;
--------------------------------------------------------
| Id | Operation | Name | A-Rows | Buffers |
--------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 13 |
|* 1 | COUNT STOPKEY | | 1 | 13 |
| 2 | TABLE ACCESS SAMPLE| T1 | 1 | 13 |
--------------------------------------------------------
데이터 분포를 확인하기 위해 앞선 쿼리를 10,000번 수행한 결과를 t3 테이블에 저장하겠습니다. 수행에 10.28초가 소요됩니다.
-- 6
TRUNCATE TABLE t2;
BEGIN
FOR i IN 1 .. 10000 LOOP
INSERT
INTO t2
SELECT *
FROM t1 SAMPLE BLOCK (1)
WHERE ROWNUM = 1;
END LOOP;
COMMIT;
END;
/
PL/SQL 처리가 정상적으로 완료되었습니다.
경 과: 00:00:10.28
t3 테이블의 백분위 비율을 조회하면 SAMPLE 절에 비해 데이터 분포가 넓지만 대부분의 데이터가 1에서 5,000,000 사이에 분포되어 있음을 알 수 있습니다.
-- 7
SELECT CEIL (c1 / 100000) AS c1
, COUNT (*) AS cnt
FROM t2
GROUP BY CEIL (c1 / 100000)
ORDER BY c1;
C1 CNT
-- ----
1 1088
2 1076
...
46 9
56 8
42 행이 선택되었습니다.
DBMS_RANDOM.VALUE 함수
PK가 순번이면 DBMS_RANDOM.VALUE 함수로 키 값을 생성할 수 있습니다. 아래 쿼리는 DBMS_RANDOM.VALUE 함수로 로우를 랜덤하게 조회합니다. 4개의 블록 I/O가 발생합니다.
-- 8
SELECT *
FROM t1
WHERE c1 = CEIL (DBMS_RANDOM.VALUE (1, 10000000));
----------------------------------------------------------------
| Id | Operation | Name | A-Rows | Buffers |
----------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 4 |
| 1 | TABLE ACCESS BY INDEX ROWID| T1 | 1 | 4 |
|* 2 | INDEX UNIQUE SCAN | T1_U1 | 1 | 3 |
----------------------------------------------------------------
데이터 분포를 확인하기 위해 앞선 쿼리를 10,000번 수행한 결과를 t4 테이블에 저장하겠습니다. 수행에 3.08초가 소요됩니다.
-- 9
TRUNCATE TABLE t2;
BEGIN
FOR i IN 1 .. 10000 LOOP
INSERT
INTO t2
SELECT *
FROM t1
WHERE c1 = CEIL (DBMS_RANDOM.VALUE (1, 10000000));
END LOOP;
COMMIT;
END;
/
PL/SQL 처리가 정상적으로 완료되었습니다.
경 과: 00:00:03.08
t4 테이블의 백분위 비율을 조회하면 데이터 분포가 균등한 것을 확인할 수 있습니다.
-- 10
SELECT CEIL (c1 / 100000) AS c1
, COUNT (*) AS cnt
FROM t2
GROUP BY CEIL (c1 / 100000)
ORDER BY c1;
C1 CNT
--- ---
1 95
2 98
...
99 106
100 113
100 행이 선택되었습니다.
결과
아래 표는 앞서 테스트한 결과를 보여줍니다.
방식 | 블록 I/O | 수행시간 (10,000번) | 데이터 분포 |
SAMPLE 절 | 3 | 7.58 | 매우 나쁨 |
SAMPLE BLOCK 절 | 13 | 10.28 | 나쁨 |
DBMS_RANDOM.VALUE 함수 | 4 | 3.08 | 매우 좋음 |
관련 링크