2014-03-31 2 views
0

데이터베이스에 약 백만 레코드가있는 레코드 테이블이 있습니다. 대부분의 기록은 공개되어있어 시스템의 모든 사용자가 볼 수 있습니다. 그러나 똑같은 테이블에서 개인 레코드도 있습니다. 일반적으로 각 사용자별로 수백 개의 레코드가 있습니다. 나는 시스템에 약 1K 명의 사용자가있다. - 레코드 ID의 열거SQL Server 2008 - 동일한 테이블에서 공용 및 개인 레코드를 처리하는 가장 좋은 방법

  • ID :

    각 레코드는 3 주 열이 있습니다. 고유 기본 키.

  • UserID - 레코드 소유자를 식별합니다. Null = 모든 사람이 사용할 수있는 일반 레코드. ID =이 특정 사용자 ID에 대해서만 사용 가능한 개인 레코드.
  • RecID - 공공 기록 ID. 모든 공개 기록에 고유합니다. 사용자가 공용 레코드를 변경하면 시스템은이 레코드를 새 ID로 복제하지만 동일한 RecID을 복제합니다.

ID RecID UserID Comments 
---------------------------------------------------------------------------- 
1 1000 NULL General record 
2 1000 1 Modification of record ID=1, available only for userID=1 
3 1001 NULL General Record 
4 1002 NULL General Record 
5 1001 2 Modification of record ID=3, available only for userID=2 
  • 시스템에 사용자 1 로그, 그는 기록 2,3,4의 목록을해야하는 경우
  • 시스템에 사용자 2 로그, 그는 받아야하는 경우 기록 1,4,5 목록
  • 시스템에 사용자 3 로그, 그는 기록의 목록을해야하는 경우 1,3,4

내가 사용하는 쿼리는 다음과 같습니다 :

SELECT * 
FROM TB_Records 
WHERE UserID = @UserID 
    OR (RecID IS NULL AND NOT RecID IN (SELECT RecID 
             FROM TB_Records 
             WHERE UserID = @UserID) 

성능에 문제가 있습니다. 이 쿼리 위에 필터링 및 페이징 결과를 정렬하여 각 선택에 대해 5-10 초의 성능을 추가합니다. 모든 레코드를 선택하면 쿼리의 세 번째 줄을 제거 할 때 성능이 훨씬 좋아집니다 (1-2 초).

이러한 요구 사항을 처리하는 더 좋은 방법이 있는지 알고 싶습니다.

감사합니다.

+0

당신이 사용자 ID에 클러스터되지 않은 인덱스를 가지고 있나요 : 때때로, 그것은 union all와 쿼리 or 더 나은 이상을 최적화 할 것인가? 추가 한 경우 성능이 향상됩니다. 다른 해결책이 있지만 그 질문은 첫 번째 질문입니다. –

답변

1

이 쿼리는 의미가 없습니다. NULL 값이 RecID 일 때 예상대로 작동하지 않으므로 AND NOT 부분은 필요하지 않습니다. 제 말은 다음과 같습니다.

SELECT r.* 
FROM TB_Records r 
WHERE r.UserID = @UserID OR 
     (r.UserId IS NULL AND NOT r.RecID IN (SELECT r2.RecID 
              FROM TB_Records r2 
              WHERE r2.UserID = @UserID) 

우선 색인을 TB_Records(UserId, RecId)에 만듭니다. 그게 도움이 될거야. 다음으로, 명시 적 left outer join이 변경하려고 할 것입니다 :

select r.* 
from TB_Records r left outer join 
    TB_Records r2 
    on r2.UserId = @UserId and 
     r2.RecId = r.RecId 
where r.UserId = @UserId or r2.RecId is NULL; 

편집 :

한 번 더 시도, 다른 접근 방식. 이 함수는 창 함수를 사용하여 사용자가 주어진 레코드에 대해 존재하는지 확인합니다.

select r.* 
from (select r.*, 
      max(case when r.UserId = @UserId then 1 else 0 end) over (partition by RecId) as HasUser 
     from TB_Records r 
    ) t 
where r.UserId = @UserId or HasUser = 0; 

그렇지 않으면 실행 계획을 질문에 넣어야합니다.

select r.* 
from TB_Records r 
where r.UserId = @UserId 
union all 
select r.* 
from TB_Records r left outer join 
    TB_Records r2 
    on r2.UserId = @UserId and 
     r2.RecId = r.RecId 
where r2.RecId is NULL; 
+0

안녕하세요. 내 전체 쿼리 및 성능에 동일한 시도했다. 다른 아이디어는 더 빨리 달릴 수 있습니까? – user1395570