[sql] SQL Server 테이블에서 n 개의 임의 행을 선택하십시오.

약 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 데이터베이스에 복사되어 정렬됩니다. 이로 인해 두 가지 문제가 발생합니다.

  1. 정렬 작업에는 일반적으로 관련 비용이 높습니다. 정렬은 많은 디스크 I / O를 사용할 수 있으며 오랫동안 실행될 수 있습니다.
  2. 최악의 경우 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()전화가 충분합니다-모든 캐스트와 수학이 필요하지 않습니다.