JOON 절에서 OR를 사용하는 것보다 UNIONing 두 결과 집합이 더 나은 이유를 보여주기 위해 샘플 쿼리 계획을 작성하려고합니다. 내가 작성한 쿼리 계획으로 인해 문제가 발생했습니다. Users.Reputation에서 비 클러스터형 인덱스가있는 StackOverflow 데이터베이스를 사용하고 있습니다.
CREATE NONCLUSTERED INDEX IX_NC_REPUTATION ON dbo.USERS(Reputation)
SELECT DISTINCT Users.Id
FROM dbo.Users
INNER JOIN dbo.Posts
ON Users.Id = Posts.OwnerUserId
OR Users.Id = Posts.LastEditorUserId
WHERE Users.Reputation = 5
쿼리 계획은 https://www.brentozar.com/pastetheplan/?id=BkpZU1MZE에 있으며, 쿼리 지속 시간은 4:37 분이며 26612 행이 반환됩니다.
이전에 기존 테이블에서 이러한 유형의 상수 스캔이 생성되는 것을 보지 못했습니다. 사용자가 입력 한 단일 행에 대해 일정한 스캔이 일반적으로 사용될 때 모든 단일 행에 대해 연속 스캔이 실행되는 이유에 익숙하지 않습니다. 예를 들어, SELECT GETDATE (). 왜 여기에 사용됩니까? 이 쿼리 계획을 읽는 데 도움이 될만한 조언을 부탁드립니다.
그 OR을 UNION으로 분리하면 동일한 26612 행이 반환 된 12 초 안에 실행되는 표준 계획이 생성됩니다.
SELECT Users.Id
FROM dbo.Users
INNER JOIN dbo.Posts
ON Users.Id = Posts.OwnerUserId
WHERE Users.Reputation = 5
UNION
SELECT Users.Id
FROM dbo.Users
INNER JOIN dbo.Posts
ON Users.Id = Posts.LastEditorUserId
WHERE Users.Reputation = 5
이 계획을 다음과 같이 해석합니다.
- 게시물에서 41782500 행을 모두 가져옵니다 (실제 행 수는 게시물의 CI 스캔과 일치합니다)
- 게시물의 각 41782500 행에 대해 :
- 스칼라 생성 :
- Expr1005 : OwnerUserId
- Expr1006 : OwnerUserId
- Expr1004 : 정적 값 62
- Expr1008 : LastEditorUserId
- Expr1009 : LastEditorUserId
- Expr1007 : 정적 값 62
- 연결에서 :
- Exp1010 : Expr1005 (OwnerUserId)가 널이 아닌 경우 Expr1008 (LastEditorUserID)을 사용하십시오.
- Expr1011 : Expr1006 (OwnerUserId)이 널이 아닌 경우 Expr1009 (LastEditorUserId)를 사용하십시오.
- Expr1012 : Expr1004 (62)가 null이면 Expr1007 (62)을 사용하십시오.
- Compute 스칼라에서 : 앰퍼샌드가 무엇을하는지 모르겠습니다.
- Expr1013 : 4 [and?] 62 (Expr1012) = 4이고 OwnerUserId는 NULL입니다 (NULL = Expr1010)
- expr1014 : 4 [및?] 62 (Expr1012)
- Expr1015 : 16 및 62 (Expr1012)
- 정렬 기준 :
- Expr1013 설명
- Expr1014 Asc
- Expr1010 Asc
- Expr1015 설명
- 병합 간격에서 Expr1013 및 Expr1015를 제거했습니다 (이것은 입력이지만 출력은 아닙니다)
- 인덱스 탐색 아래의 중첩 루프 조인에서 Expr1010과 Expr1011을 탐색 술어로 사용하고 있지만 IX_NC_REPUTATION에서 Expr1010 및 Expr1011이 포함 된 하위 트리로 중첩 루프 조인을 수행하지 않은 경우 어떻게 액세스 할 수 있는지 이해할 수 없습니다. .
- 중첩 루프 조인은 이전 하위 트리에서 일치하는 Users.ID 만 반환합니다. 술어 푸시 다운으로 인해 IX_NC_REPUTATION의 인덱스 검색에서 리턴 된 모든 행이 리턴됩니다.
- 마지막 중첩 루프 조인 : 각 게시물 레코드에 대해 아래 데이터 집합에서 일치하는 Users.Id를 출력합니다.
SELECT Users.Id FROM dbo.Users WHERE Users.Reputation = 5 AND EXISTS (SELECT 1 FROM dbo.Posts WHERE Users.Id IN (Posts.OwnerUserId, Posts.LastEditorUserId) ) ;
SELECT Users.Id FROM dbo.Users WHERE Users.Reputation = 5 AND ( EXISTS (SELECT 1 FROM dbo.Posts WHERE Users.Id = Posts.OwnerUserId) OR EXISTS (SELECT 1 FROM dbo.Posts WHERE Users.Id = Posts.LastEditorUserId) ) ;