다음과 같은 쿼리가 있습니다.
DELETE FROM tblFEStatsBrowsers WHERE BrowserID NOT IN (
SELECT DISTINCT BrowserID FROM tblFEStatsPaperHits WITH (NOLOCK) WHERE BrowserID IS NOT NULL
)
tblFEStatsBrowsers에 553 개의 행이 있습니다.
tblFEStatsPaperHits에 47.974.301 개의 행이 있습니다.
브라우저 :
CREATE TABLE [dbo].[tblFEStatsBrowsers](
[BrowserID] [smallint] IDENTITY(1,1) NOT NULL,
[Browser] [varchar](50) NOT NULL,
[Name] [varchar](40) NOT NULL,
[Version] [varchar](10) NOT NULL,
CONSTRAINT [PK_tblFEStatsBrowsers] PRIMARY KEY CLUSTERED ([BrowserID] ASC)
)
tblFEStatsPaperHits :
CREATE TABLE [dbo].[tblFEStatsPaperHits](
[PaperID] [int] NOT NULL,
[Created] [smalldatetime] NOT NULL,
[IP] [binary](4) NULL,
[PlatformID] [tinyint] NULL,
[BrowserID] [smallint] NULL,
[ReferrerID] [int] NULL,
[UserLanguage] [char](2) NULL
)
tblFEStatsPaperHits에는 BrowserID가 포함되지 않은 클러스터형 인덱스가 있습니다. 따라서 내부 쿼리를 수행하려면 tblFEStatsPaperHits의 전체 테이블 스캔이 필요합니다.
현재 tblFEStatsBrowsers의 각 행에 대해 전체 스캔이 실행됩니다. 즉, tblFEStatsPaperHits에 대한 553 개의 전체 테이블 스캔이 있습니다.
기존 위치에 다시 쓰더라도 계획은 변경되지 않습니다.
DELETE FROM tblFEStatsBrowsers WHERE NOT EXISTS (
SELECT * FROM tblFEStatsPaperHits WITH (NOLOCK) WHERE BrowserID = tblFEStatsBrowsers.BrowserID
)
그러나 Adam Machanic이 제안한대로 HASH JOIN 옵션을 추가하면 최적의 실행 계획이 생성됩니다 (tblFEStatsPaperHits의 단일 스캔).
DELETE FROM tblFEStatsBrowsers WHERE NOT EXISTS (
SELECT * FROM tblFEStatsPaperHits WITH (NOLOCK) WHERE BrowserID = tblFEStatsBrowsers.BrowserID
) OPTION (HASH JOIN)
이제 이것은이 문제를 해결하는 방법에 대한 질문이 아닙니다 .OPTION (HASH JOIN)을 사용하거나 임시 테이블을 수동으로 만들 수 있습니다. 쿼리 최적화 프로그램이 현재 계획을 사용하는 이유가 더 궁금합니다.
QO에는 BrowserID 열에 통계가 없으므로 최악의 5 천만 개의 고유 값을 가정하므로 상당히 큰 메모리 내 / tempdb 작업 테이블이 필요하다고 생각합니다. 따라서 가장 안전한 방법은 tblFEStatsBrowsers에서 각 행에 대한 스캔을 수행하는 것입니다. 두 테이블의 BrowserID 열간에 외래 키 관계가 없으므로 QO는 tblFEStatsBrowsers에서 정보를 빼낼 수 없습니다.
이것이 들리는 것처럼 간단합니까?
업데이트 1
몇 가지 통계를 제공하려면 : OPTION (HASH JOIN) :
208.711 논리적 읽기 (12 회 스캔)
옵션 (루프 가입, 해시 그룹) :
11.008.698 논리적 읽기 (~ 브라우저 ID 당 스캔 (339))
옵션 없음 :
11.008.775 논리적 읽기 (브라우저 ID 당 ~ scan (339))
업데이트 2
훌륭한 답변, 모두 감사합니다! 하나만 고르기가 힘들다. Martin은 처음이었고 Remus는 훌륭한 솔루션을 제공하지만 세부 사항을 염두에두고 키위에 제공해야합니다. :)