[SQL] SQL 데이터베이스에서 단순 무작위 샘플
SQLSQL 데이터베이스에서 단순 무작위 샘플
어떻게 SQL의 효율적인 단순 무작위 표본을합니까? 문제의 데이터베이스는 MySQL이 실행되고; 내 표는 적어도 20 행이며, 나는 10,000 정도의 단순 무작위 표본을 원한다.
은 "명백한"대답하는 것입니다 :
SELECT * FROM table ORDER BY RAND() LIMIT 10000
너무 느린 대형 테이블의 경우, : 베스트에 그것을 O (N LG 전자 N)를 제작해야합니다 (이미 O (N)에 넣는다) 모든 행에 대한 RAND ()를 호출하고 정렬합니다. O (n)을보다 빠르게 할 수있는 방법이 있습니까?
참고 : RAND ()가 모든 행에 대해 동일한 값을 반환 할 수 있기 때문에 당신은 SQL Server에서이 방법을 사용하는 경우로서 앤드류 마오는 코멘트에 지적, 당신은 T-SQL 기능 NEWID ()를 사용한다.
편집 : 5 년 후
나는 더 큰 테이블에 다시이 문제로 실행, 그리고 버전을 사용하여 종료 @의 무지 솔루션을 두 개조하면 되겠와 함께 :
테이블의 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 주위를 포장하지 않는 undersample,과에 확인하기 위해 더 많은 작업을 포함하지만, 기본적인 아이디어는 "무작위로 몇 천까지 당신의 N 컷"입니다.)
이 어떤 희생을 기울이고 있으나,이 정도로 작은 ()가 다시 ORDER BY RAND에 때까지, 그것은 나를 인덱스 스캔을 사용하여 아래로 데이터베이스를 샘플링 할 수 있습니다.
해결법
-
==============================
1.이러한 유형의 문제의 매우 흥미로운 토론이 여기에있다 : http://www.titov.net/2005/09/21/do-not-use-order-by-rand-or-how-to-get-random- 행-에서 테이블 /
이러한 유형의 문제의 매우 흥미로운 토론이 여기에있다 : http://www.titov.net/2005/09/21/do-not-use-order-by-rand-or-how-to-get-random- 행-에서 테이블 /
나는 당신의 O (N LG 전자 N) 솔루션은 최고라고 테이블에 대해 전혀 가정으로 생각합니다. 비록 실제로 좋은 최적화 또는 약간 다른 기술 쿼리하면 목록 조금 더있을 수 있습니다, O (m * n)이이 necesssarily 전체 큰 배열을 정렬 할 필요가없는 것처럼 m은 임의의 행의 수를 원하는 것입니다 , 그냥 작은 m 시간을 검색 할 수 있습니다. 그러나 당신이 게시 번호의 종류를 위해, m은 n은 어쨌든 LG 전자보다 크다.
세 가지 가정을 우리는 밖으로 시도 할 수 있습니다 :
단지 가정 1과 2를 당신이 가정 3 일치하도록 테이블에 전체 인덱스를 작성해야하지만이 necesarily 빠른 O (n)이없는, 그래서이, O (N)으로 수행 할 수 있다고 생각합니다. 우리는 또한 테이블에 대해 뭔가 다른 좋은 가정 할 수 있다면, 우리는 O의 작업 (m 로그 m)를 할 수 있습니다. 가정 3 작업하기 쉬운 좋은 속성이 추가 될 것이다. 행 번호 m을 생성하는 경우에는 중복 보장되는 좋은 난수 발생기로하는 O (m) 용액이 가능할 것이다.
세 가지 가정을 감안할 때, 기본적인 아이디어는 1과 N 사이 m 고유 한 난수를 생성 한 후 테이블에서 해당 키를 사용하여 행을 선택하는 것입니다. 나는 약간처럼 보일 것이있는 의사 정도면, 지금 내 앞에 MySQL의 또는 아무것도하지 않습니다
create table RandomKeys (RandomKey int) create table RandomKeysAttempt (RandomKey int) -- generate m random keys between 1 and n for i = 1 to m insert RandomKeysAttempt select rand()*n + 1 -- eliminate duplicates insert RandomKeys select distinct RandomKey from RandomKeysAttempt -- as long as we don't have enough, keep generating new keys, -- with luck (and m much less than n), this won't be necessary while count(RandomKeys) < m NextAttempt = rand()*n + 1 if not exists (select * from RandomKeys where RandomKey = NextAttempt) insert RandomKeys select NextAttempt -- get our random rows select * from RandomKeys r join table t ON r.RandomKey = t.UniqueKey
당신은 정말 효율성에 대해 우려한다면, 당신은 아마의 종류에 더 좋을 것이다 SQL 이외의 거의 아무것도, 절차 적 언어의 어떤 종류의 랜덤 키 생성을 수행하고 데이터베이스에 결과를 삽입하는 것이 좋습니다 루핑 및 난수 생성이 필요합니다 .
-
==============================
2.나는 가장 빠른 해결책이 생각
나는 가장 빠른 해결책이 생각
select * from table where rand() <= .3
나는이 일을해야한다고 생각하는 이유 여기에있다.
이것은 그 랜드 가정 ()은 균일 한 분포의 숫자를 생성한다. 그것은이 작업을 수행 할 수있는 가장 빠른 방법입니다.
여기 내가 그에게 말할 것입니다 .. 그 사람이 그 솔루션을 추천했다 그들은 증거없이 아래로 총에 맞았 보았다 -
문제의 데이터베이스는 MySQL이 있기 때문에, 이것이 바로 솔루션입니다.
-
==============================
3.그냥 사용
그냥 사용
WHERE RAND() < 0.1
기록의 10 %를 얻기 위해 또는
WHERE RAND() < 0.01
등을 기록, 1 %를 얻을 수 있습니다
-
==============================
4.분명히 SQL의 일부 버전에서 TABLESAMPLE 명령있다,하지만 모든 SQL 구현 (특히, Redshift에)에 아니에요.
분명히 SQL의 일부 버전에서 TABLESAMPLE 명령있다,하지만 모든 SQL 구현 (특히, Redshift에)에 아니에요.
http://technet.microsoft.com/en-us/library/ms189108(v=sql.105).aspx
-
==============================
5.나는 따라서는 O (n)이 시간에 실행, 그래서 감동 빠른 수행,이 방법은 ORDER BY RAND ()보다 훨씬 더 빨리 테스트.
나는 따라서는 O (n)이 시간에 실행, 그래서 감동 빠른 수행,이 방법은 ORDER BY RAND ()보다 훨씬 더 빨리 테스트.
http://technet.microsoft.com/en-us/library/ms189108%28v=sql.105%29.aspx에서 :
비 MSSQL 버전 -이 테스트를하지 않았다
SELECT * FROM Sales.SalesOrderDetail WHERE 0.01 >= RAND()
MSSQL 버전 :
SELECT * FROM Sales.SalesOrderDetail WHERE 0.01 >= CAST(CHECKSUM(NEWID(), SalesOrderID) & 0x7fffffff AS float) / CAST (0x7fffffff AS int)
이 기록의 ~ 1 %를 선택합니다. 당신이 선택할 수 퍼센트 나 기록의 정확한 # 필요 그렇다면, 몇 가지 안전 여유와 비율을 추정 한 후 무작위로 세트를 결과 RAND () 메소드에 의해 더 비싼 ORDER를 사용하는 여분의 기록을 뽑아.
내가 잘 알려진 인덱스 컬럼 값의 범위를했기 때문에 나는 더욱이 방법을 개선 할 수 있었다.
만약 [0..max 균일하게 분포 정수로 인덱싱 된 열이 경우, 예를 들어, 임의로 N 작은 간격들을 선택하는 것을 사용할 수있다. 각 쿼리 실행에 대한 다른 세트를 얻을 수 있도록 프로그램이 동적으로 작업을 수행합니다. 이 부분 집합의 선택은 O (N)이 될 것이다 전체 데이터 세트보다 작은 크기의 수 많은 주문.
내 테스트에서 나는 0.0 초까지 20 ORDER BY RAND ()를 사용하여 3 분의 샘플 기록 (MIL 20에서)를 얻기 위해 필요한 시간을 감소!
-
==============================
6.나는이 모든 솔루션 교체없이 샘플에 표시 것을 지적하고 싶다. 임의의 종류에서 최고 K 행을 선택 또는 교체없이 생성 된 임의의 샘플을 얻을 것입니다 무작위로 고유 키를 포함하는 테이블에 합류.
나는이 모든 솔루션 교체없이 샘플에 표시 것을 지적하고 싶다. 임의의 종류에서 최고 K 행을 선택 또는 교체없이 생성 된 임의의 샘플을 얻을 것입니다 무작위로 고유 키를 포함하는 테이블에 합류.
당신이 당신의 샘플이 독립하려는 경우, 당신은 대체 샘플해야합니다. A는 user12861의 솔루션과 유사한 방식으로 가입하여이 작업을 수행하는 방법의 한 예를 들어 질문 25451034를 참조하십시오. 이 솔루션은 T-SQL 용으로 작성되어 있지만 개념은 모든 SQL DB에서 작동합니다.
-
==============================
7.우리는 테이블의 ID를 검색 할 수있는 관찰을 시작으로 집합을 기반으로 (예 : 5를 계산합니다.)
우리는 테이블의 ID를 검색 할 수있는 관찰을 시작으로 집합을 기반으로 (예 : 5를 계산합니다.)
select * from table_name where _id in (4, 1, 2, 5, 3)
우리는 우리가 "(4, 1, 2, 5, 3)"문자열을 생성 할 수 있다면, 우리는 RAND보다 더 효율적인 방법을 할 것이다, 그 결과로 올 수 있습니다 ().
예를 들어, 자바 :
ArrayList<Integer> indices = new ArrayList<Integer>(rowsCount); for (int i = 0; i < rowsCount; i++) { indices.add(i); } Collections.shuffle(indices); String inClause = indices.toString().replace('[', '(').replace(']', ')');
IDS는 간격이 있다면, 초기의 ArrayList 지수는 IDS에 SQL 쿼리의 결과입니다.
-
==============================
8.정확히 행을 해요 필요가있는 경우, 현실적으로는 SQL의 ID를 외부의 당신의 부분 집합을 생성 할 수 있습니다. 대부분의 방법은 "n 번째"항목을 선택하려면 어떤 점에서 필요로하며, SQL 테이블은 정말 전혀 배열되지 않습니다. 키가 불과하기 위해 연속 있다는 가정은 1 사이의 임의의 int에 가입하고 계산도 만족하기 어려운 - MySQL은, 예를 들어 기본적으로 지원하지 않으며, 잠금 조건은 ... 까다로운.
정확히 행을 해요 필요가있는 경우, 현실적으로는 SQL의 ID를 외부의 당신의 부분 집합을 생성 할 수 있습니다. 대부분의 방법은 "n 번째"항목을 선택하려면 어떤 점에서 필요로하며, SQL 테이블은 정말 전혀 배열되지 않습니다. 키가 불과하기 위해 연속 있다는 가정은 1 사이의 임의의 int에 가입하고 계산도 만족하기 어려운 - MySQL은, 예를 들어 기본적으로 지원하지 않으며, 잠금 조건은 ... 까다로운.
다음은 O입니다 (최대 (N, m LG 전자 N)) - 시간, 그냥 일반 BTREE 키를 가정 O (N) - 공간 솔루션 :
SQL의 임의의 부분 집합의 외부를 발생시키는 방법은 적어도 이러한 복잡성이 있어야합니다. 더 빨리 O 이상 (m LG N)와 BTREE (그래서 O (m) 주장은 대부분의 엔진에 대한 환상이다)이 될 수 없습니다 가입하고 셔플은 아래 묶여있다 n과 m LG 전자 N과 점근 동작에 영향을주지 않습니다.
파이썬 의사 코드에서 :
ids = sql.query('SELECT id FROM t') for i in range(m): r = int(random() * (len(ids) - i)) ids[i], ids[i + r] = ids[i + r], ids[i] results = sql.query('SELECT * FROM t WHERE id IN (%s)' % ', '.join(ids[0:m-1])
-
==============================
9.네티 3000 개 무작위 기록을 선택합니다 :
네티 3000 개 무작위 기록을 선택합니다 :
WITH IDS AS ( SELECT ID FROM MYTABLE; ) SELECT ID FROM IDS ORDER BY mt_random() LIMIT 3000
-
==============================
10.어쩌면 당신은 할 수
어쩌면 당신은 할 수
SELECT * FROM table LIMIT 10000 OFFSET FLOOR(RAND() * 190000)
from https://stackoverflow.com/questions/249301/simple-random-samples-from-a-sql-database by cc-by-sa and MIT license
'SQL' 카테고리의 다른 글
[SQL] SQL에서의 나쁜 성능을 위해인가? (0) | 2020.03.29 |
---|---|
[SQL] SQL 성능 UNION 대 또는 (0) | 2020.03.29 |
[SQL] 그것은 재귀 SQL 쿼리를 만들 수 있습니까? (0) | 2020.03.29 |
[SQL] SQLite는에 변수를 선언하고 사용 (0) | 2020.03.29 |
[SQL] SQL 서버 : 적절한 케이스 / 타이틀 케이스에 모든 UPPER 사례를 확인 (0) | 2020.03.29 |