약 50,000 개의 행이있는 SQL Server 테이블이 있습니다. 그 행 중 약 5,000 행을 무작위로 선택하고 싶습니다. 복잡한 방법을 생각했습니다. “임의의 숫자”열이있는 임시 테이블을 생성하고 테이블을 복사하고 임시 테이블을 반복하고 각 행을로 업데이트 RAND()
한 다음 난수 열이 < 0.1. 가능한 한 단일 진술로 더 간단한 방법을 찾고 있습니다.
이 기사 는 NEWID()
함수 사용을 제안 합니다. 유망한 것처럼 보이지만 특정 비율의 행을 안정적으로 선택할 수있는 방법을 알 수 없습니다.
아무도 전에 이것을 한 적이 있습니까? 어떤 아이디어?
답변
select top 10 percent * from [yourtable] order by newid()
큰 테이블에 대한 “순수한 휴지통”주석에 대한 응답으로 성능을 향상시키기 위해 이와 같이 할 수 있습니다.
select * from [yourtable] where [yourPk] in
(select top 10 percent [yourPk] from [yourtable] order by newid())
이 비용은 값의 주요 스캔 + 결합 비용으로, 적은 비율로 선택하는 큰 테이블에서는 합리적이어야합니다.
답변
필요에 따라 TABLESAMPLE
거의 임의적이고 더 나은 성능을 얻을 수 있습니다. MS SQL Server 2005 이상에서 사용할 수 있습니다.
TABLESAMPLE
임의의 행 대신 임의의 페이지에서 데이터를 반환하므로 반환하지 않는 데이터는 검색하지 않습니다.
매우 큰 테이블에서 테스트했습니다
select top 1 percent * from [tablename] order by newid()
20 분 이상 걸렸습니다.
select * from [tablename] tablesample(1 percent)
2 분이 걸렸습니다.
작은 샘플에서는 성능이 향상되는 TABLESAMPLE
반면, 그렇지 않은 경우에는 성능이 향상됩니다 newid()
.
이것은 newid()
방법 만큼 무작위 적이지는 않지만 적절한 샘플링을 제공 한다는 점을 명심하십시오 .
참고 항목 MSDN 페이지를 .
답변
newid () / order by는 작동하지만 모든 행에 대해 id를 생성 한 다음 정렬해야하기 때문에 큰 결과 집합에는 비용이 많이 듭니다.
TABLESAMPLE ()은 성능 관점에서는 좋지만 결과가 뭉치 게됩니다 (페이지의 모든 행이 반환 됨).
더 나은 성능의 실제 무작위 샘플을 얻으려면 가장 좋은 방법은 행을 무작위로 필터링하는 것입니다. SQLS 온라인 설명서의 TABLESAMPLE을 사용하여 결과 집합 제한 에서 다음 코드 샘플을 찾았습니다 .
개별 행의 임의 샘플을 실제로 원한다면 TABLESAMPLE을 사용하는 대신 무작위로 행을 필터링하도록 쿼리를 수정하십시오. 예를 들어 다음 쿼리는 NEWID 함수를 사용하여 Sales.SalesOrderDetail 테이블 행의 약 1 %를 반환합니다.
SELECT * FROM Sales.SalesOrderDetail WHERE 0.01 >= CAST(CHECKSUM(NEWID(),SalesOrderID) & 0x7fffffff AS float) / CAST (0x7fffffff AS int)
SalesOrderID 열은 CHECKSUM 표현식에 포함되므로 NEWID ()가 행당 한 번 평가되어 행별로 샘플링을 수행 할 수 있습니다. CAST (CHECKSUM (NEWID (), SalesOrderID) & 0x7fffffff AS float / CAST (0x7fffffff AS int) 식은 0과 1 사이의 임의의 부동 소수점 값으로 평가됩니다.
1,000,000 개의 행이있는 테이블에 대해 실행할 때 내 결과는 다음과 같습니다.
SET STATISTICS TIME ON
SET STATISTICS IO ON
/* newid()
rows returned: 10000
logical reads: 3359
CPU time: 3312 ms
elapsed time = 3359 ms
*/
SELECT TOP 1 PERCENT Number
FROM Numbers
ORDER BY newid()
/* TABLESAMPLE
rows returned: 9269 (varies)
logical reads: 32
CPU time: 0 ms
elapsed time: 5 ms
*/
SELECT Number
FROM Numbers
TABLESAMPLE (1 PERCENT)
/* Filter
rows returned: 9994 (varies)
logical reads: 3359
CPU time: 641 ms
elapsed time: 627 ms
*/
SELECT Number
FROM Numbers
WHERE 0.01 >= CAST(CHECKSUM(NEWID(), Number) & 0x7fffffff AS float)
/ CAST (0x7fffffff AS int)
SET STATISTICS IO OFF
SET STATISTICS TIME OFF
TABLESAMPLE을 사용하여 벗어날 수 있다면 최상의 성능을 제공합니다. 그렇지 않으면 newid () / filter 메소드를 사용하십시오. 결과 세트가 큰 경우 newid () / order by를 최후의 수단으로 사용해야합니다.
답변
MSDN 의 큰 테이블 에서 무작위로 행 선택하기 대규모 성능 문제를 해결하는 간단하고 잘 설명 된 솔루션이 있습니다.
SELECT * FROM Table1
WHERE (ABS(CAST(
(BINARY_CHECKSUM(*) *
RAND()) as int)) % 100) < 10
답변
이 링크는 Orderby (NEWID ())와 1, 7, 1,300 만 행의 테이블에 대한 다른 메소드를 흥미롭게 비교합니다.
토론 그룹에서 임의 행을 선택하는 방법에 대한 질문이있을 때 종종 NEWID 쿼리가 제안됩니다. 간단하고 작은 테이블에 매우 효과적입니다.
SELECT TOP 10 PERCENT *
FROM Table1
ORDER BY NEWID()
그러나 NEWID 쿼리는 큰 테이블에 사용할 때 큰 단점이 있습니다. ORDER BY 절은 테이블의 모든 행이 tempdb 데이터베이스에 복사되어 정렬됩니다. 이로 인해 두 가지 문제가 발생합니다.
- 정렬 작업에는 일반적으로 관련 비용이 높습니다. 정렬은 많은 디스크 I / O를 사용할 수 있으며 오랫동안 실행될 수 있습니다.
- 최악의 경우 tempdb에 공간이 부족할 수 있습니다. 최상의 시나리오에서 tempdb는 수동 축소 명령 없이는 다시 확보 할 수없는 디스크 공간을 많이 차지할 수 있습니다.
필요한 것은 tempdb를 사용하지 않고 테이블이 커질수록 훨씬 느려지지 않는 행을 무작위로 선택하는 방법입니다. 이를 수행하는 방법에 대한 새로운 아이디어는 다음과 같습니다.
SELECT * FROM Table1
WHERE (ABS(CAST(
(BINARY_CHECKSUM(*) *
RAND()) as int)) % 100) < 10
이 쿼리의 기본 개념은 테이블의 각 행에 대해 0에서 99 사이의 난수를 생성 한 다음 난수가 지정된 백분율 값보다 작은 모든 행을 선택한다는 것입니다. 이 예에서는 약 10 %의 행을 임의로 선택하려고합니다. 따라서 난수가 10보다 작은 모든 행을 선택합니다.
MSDN 의 전체 기사를 읽으십시오 .
답변
OP와 달리 특정 수의 레코드가 필요하고 (CHECKSUM 접근 방식을 어렵게 함) TABLESAMPLE 자체가 제공하는 것보다 더 임의의 샘플을 원하고 CHECKSUM보다 더 빠른 속도를 원하는 경우, 다음과 같은 TABLESAMPLE 및 NEWID () 메소드
DECLARE @sampleCount int = 50
SET STATISTICS TIME ON
SELECT TOP (@sampleCount) *
FROM [yourtable] TABLESAMPLE(10 PERCENT)
ORDER BY NEWID()
SET STATISTICS TIME OFF
제 경우에는 이것이 무작위성 (실제로 아는 것은 아닙니다)과 속도 사이의 가장 직접적인 타협입니다. TABLESAMPLE 백분율 (또는 행)을 적절하게 변경하십시오. 백분율이 높을수록 샘플이 더 무작위 적이지만 속도가 선형으로 떨어질 것으로 예상합니다. (TableSAMPLE은 변수를 허용하지 않습니다)
답변
임의의 숫자로 테이블을 정렬하고를 사용하여 처음 5,000 행을 얻으십시오 TOP
.
SELECT TOP 5000 * FROM [Table] ORDER BY newid();
최신 정보
그냥 시도하고 newid()
전화가 충분합니다-모든 캐스트와 수학이 필요하지 않습니다.