SQL에서 효율적인 단순 무작위 샘플을 어떻게 얻습니까? 문제의 데이터베이스는 MySQL을 실행하고 있습니다. 내 테이블은 최소 200,000 개의 행이고 약 10,000 개의 간단한 무작위 샘플을 원합니다.
"명백한"대답은 다음과 같습니다.
SELECT * FROM table ORDER BY RAND() LIMIT 10000
큰 테이블의 경우 너무 느립니다. RAND()
모든 행 (이미 O (n)에 있음)을 호출 하고 정렬하여 기껏해야 O (n lg n)로 만듭니다. O (n)보다 빠르게 수행 할 수있는 방법이 있습니까?
참고 : Andrew Mao가 주석에서 지적했듯이 SQL Server에서이 방법을 사용하는 경우 NEWID()
RAND () 가 모든 행에 대해 동일한 값을 반환 할 수 있으므로 T-SQL 함수를 사용해야합니다 .
편집 : 5 년 후
나는 더 큰 테이블 로이 문제에 다시 부딪 쳤고 두 가지 조정으로 @ignorant의 솔루션 버전을 사용하게되었습니다.
- 원하는 샘플 크기의 2 ~ 5 배로 행을 샘플링하여 저렴하게
ORDER BY RAND()
RAND()
삽입 / 업데이트 할 때마다 결과를 인덱싱 된 열에 저장합니다 . (데이터 세트가 업데이트가 많지 않은 경우이 열을 최신 상태로 유지하는 다른 방법을 찾아야 할 수 있습니다.)
테이블의 1000 개 항목 샘플을 가져 오기 위해 행 수를 세고 frozen_rand 열을 사용하여 평균 10,000 개 행으로 결과를 샘플링합니다.
SELECT COUNT(*) FROM table; -- Use this to determine rand_low and rand_high
SELECT *
FROM table
WHERE frozen_rand BETWEEN %(rand_low)s AND %(rand_high)s
ORDER BY RAND() LIMIT 1000
(제 실제 구현에는 언더 샘플링을 방지하고 rand_high를 수동으로 래핑하는 데 더 많은 작업이 필요하지만 기본 아이디어는 "N을 몇 천으로 무작위로 줄이는 것"입니다.)
이로 인해 약간의 희생이 발생하지만 ORDER BY RAND()
다시 충분히 작아 질 때까지 인덱스 스캔을 사용하여 데이터베이스를 샘플링 할 수 있습니다 .
RAND()
후속 호출마다 동일한 값을 반환 하기 때문에 SQL 서버에서도 작동하지 않습니다 .