2013-06-14 1 views
2

데이터 집합을보고 할 제한된 임의의 행으로 줄이기 위해 저장 프로 시저에 SQL을 작성하고 있습니다.CTE와 함께 NEWID()를 사용하여 임의의 하위 집합을 생성하면 이상한 결과가 발생합니다.

보고서는 GroupUsers이고 필터가 필요한 임의의 행의 총 수를 지정하기 위해 적용됩니다 (@SampleLimit).

  • top(@SampleLimit)는 (사용자 아이디가 여러 번 나타나는)
  • order by NEWID() 것은 넣어
  • group by UserId
  • 적용 :

    내가와 CTE (임시 테이블)을 생성하는 것으로 시작하여 원하는 결과를 얻기 임의의 순서로 결과

SQL :

; with cte_temp as 
     (select top(@SampleLimit) UserId from QueryResults 
     where (GroupId = @GroupId) 
     group by UserId order by NEWID()) 

이 결과가 설정되면 UserId가 NOT IN 인 이전 단계에서 생성 된 결과가 삭제됩니다.

delete QueryResults 
where (GroupId = @GroupId) and (UserId not in(select UserId from cte_temp)) 

난 데 문제는 때때로, 나는 예상대로 정확하게 작동 @SampleLimit과 다른 시간에 지정된 것보다 더 많은 결과를 얻을 수 있다는 것입니다.

SQL을 분해하여 응용 프로그램 외부에서 실행하려고 시도했지만 문제를 재현 할 수 없습니다.

나는 왜 내가 때때로 내가 요청한 결과를 더 많이 얻는 지 설명 할 수있는 근본적인 문제가 있습니까? 완성도를 들어

- 답변을 아래에 기반 내 재 고려 솔루션 :

select top(@SampleLimit) UserId into #T1 
from QueryResults 
where (GroupId = @GroupId) 
group by UserId 
order by NEWID() 

delete QueryResults 
where (GroupId = @GroupId) and (UserId not in(select UserId from #T1)) 
+0

에 나는'DISTINCT TOP (@SampleLimit)을 선택하는 것이 좋습니다 것이라고 참조 ...'그룹 BY''보다 빠르게 작동합니다. – Stoleg

+0

'DELETE ... UserID가 아닌 곳 (...)'후에 더 많은 결과가 남았습니까? – Stoleg

+0

@Stoleg 예, 삭제는 내가 지정한 것보다 더 많은 사용자를 남겨 둡니다. – Tanner

답변

5

그것은 NEWID() 관련된 SELECT 문이 실행됩니다 몇 번 결정적 (undeterministic)이다. 당신이 반 반이 QueryResultscte_temp 그리고 그것은 가능성이 QueryResults의 행이 있기 때문에 여러 번 다시 평가됩니다 계획에는 스풀이없는 사이에 조인 중첩 루프를 얻을 경우

이 즉, 각 외부 행 세트에 대한 즉 NOT IN과 비교되는 것은 완전히 다를 수 있습니다.

CTE를 사용하는 대신 결과를 임시 테이블로 구체화하여이를 방지 할 수 있습니다.

INSERT INTO #T 
SELECT TOP(@SampleLimit) UserId 
FROM QueryResults 
WHERE (GroupId = @GroupId) 
GROUP BY UserId 
ORDER BY NEWID() 

그런 다음 DELETE

+0

제안에 대해 감사 드리겠습니다. – Tanner

+0

이것은 보이는 것 같습니다. 일하고있어. 나는 더 많은 테스트를하고 곧 확인 하겠지만 위의 구현 이후 잘못된 계산을하지는 않았습니다. – Tanner

+0

답변을 주셔서 감사합니다. 문제가 해결되어서 fr 완전 성 질문으로 게시 한 단일 삭제 검색어로 다시 작성되었습니다. – Tanner

관련 문제