7/11 추가 MERGE JOIN 중 인덱스 스캔으로 인해 교착 상태가 발생합니다. 이 경우 FK 상위 테이블에서 전체 인덱스에 대해 S 잠금을 가져 오려는 트랜잭션이 있지만 이전에 다른 트랜잭션은 X 잠금을 인덱스의 키 값에 둡니다.
작은 예제로 시작하겠습니다 (70-461 cource의 TSQL2012 DB 사용).
CREATE TABLE [Sales].[Orders](
[orderid] [int] IDENTITY(1,1) NOT NULL,
[custid] [int] NULL,
[empid] [int] NOT NULL,
[shipperid] [int] NOT NULL,
... )
열 [custid], [empid], [shipperid]
은 [Sales].[Customers], [HR].[Employees], [Sales].[Shippers]
그에 따라 관련된 매개 변수입니다 . 각 경우에 Parrent 테이블의 참조 열에 클러스터형 인덱스가 있습니다.
ALTER TABLE [Sales].[Orders] WITH CHECK ADD CONSTRAINT [FK_Orders_Customers] FOREIGN KEY([custid]) REFERENCES [Sales].[Customers] ([custid])
ALTER TABLE [Sales].[Orders] WITH CHECK ADD CONSTRAINT [FK_Orders_Employees] FOREIGN KEY([empid]) REFERENCES [HR].[Employees] ([empid])
ALTER TABLE [Sales].[Orders] WITH CHECK ADD CONSTRAINT [FK_Orders_Shippers] FOREIGN KEY([shipperid])REFERENCES [Sales].[Shippers] ([shipperid])
외래 키를 제외하고 동일한 구조를 가진 INSERT [Sales].[Orders] SELECT ... FROM
다른 테이블을 찾으려고 합니다. 테이블을 언급하는 또 다른 중요한 것은 클러스터 된 인덱스입니다.[Sales].[OrdersCache]
[Sales].[Orders]
[Sales].[OrdersCache]
CREATE CLUSTERED INDEX idx_c_OrdersCache ON Sales.OrdersCache ( custid, empid )
소량의 데이터를 삽입하려고 할 때 예상대로 LOOP JOIN은 외래 키에서 인덱스 검색을 잘 수행합니다.
많은 양의 데이터를 사용하는 경우 쿼리 최적화 프로그램은 MERGE JOIN을 사용하여 쿼리에서 키를 유지 관리하는 가장 효율적인 방법으로 사용합니다.
그리고 우리의 경우에는 OPTION (LOOP JOIN)을 사용하여 외래 키를 사용하거나 명시적인 JOIN의 경우 INNER LOOP JOIN을 사용하여 실행하는 것과는 아무런 관련이 없습니다.
아래는 내 환경에서 실행하려는 쿼리입니다.
INSERT Sales.Orders (
custid, empid, shipperid, ... )
SELECT custid, empid, 2, ...
FROM Sales.OrdersCache
계획을 살펴보면 MERGE JOIN으로 3 개의 모든 앞쪽 키가 검증되었음을 알 수 있습니다. 전체 인덱스 잠금과 함께 INDEX SCAN을 사용하기 때문에 적절한 방법이 아닙니다.
OPTION (LOOP JOIN)을 사용하는 것은 MERGE JOIN보다 거의 15 % 더 비싸기 때문에 적합하지 않습니다 (데이터 볼륨이 증가함에 따라 회귀가 더 커질 것이라고 생각합니다).
SELECT 문에서 shipperid
삽입 된 전체 세트의 속성에 대한 단일 값을 볼 수 있습니다 . 제 생각에는 적어도 불변 속성에 대해 삽입 된 세트의 유효성 검사 단계를 더 빠르게 할 수있는 방법이 있어야합니다. 다음과 같은 것 :
- JOIN 유효성 검사에 대해 정의되지 않은 하위 집합이있는 경우 LOOP JOIN, MERGE JOIN, HASH JOIN 만들기
- 유효성 검사 열의 명시 적 값이 하나만있는 경우 유효성 검사를 한 번만 수행합니다 (INDEX SEEK).
코드 구조, 추가 DDL 객체 등을 사용하여 위의 상황을 능가하는 일반적인 패턴이 있습니까?
20/07이 추가되었습니다. 해결책. Query Optimizer는 이미 MERGE JOIN을 사용하여 '단일 키-외래 키'유효성 검증 최적화를 수행합니다. 또한 Sales.Shippers 테이블 만 만들어 쿼리의 다른 조인에 대해 LOOP JOIN을 동시에 남겨 둡니다. 부모 테이블에 몇 개의 행이 있으므로 Query Optimizer는 정렬 병합 조인 알고리즘을 사용하고 내부 테이블의 각 행을 부모 테이블과 한 번만 비교합니다. 단일 키 유효성 검사 중에 세트에서 단일 값을 효과적으로 처리하는 특정 메커니즘이 있다면 이것이 내 질문에 대한 대답입니다. 그것은 완벽한 결정은 아니지만 SQL Server가 사례를 최적화하는 방식입니다.
성능 영향 조사에 따르면 필자의 경우 MERGE JOIN 및 LOOP JOIN insert 문은 다음과 같은 MERGE JOIN (CPU 시간 리소스)보다 우월한 750 개의 동시 삽입 행과 거의 같습니다. 따라서 OPTION (LOOP JOIN)을 사용하는 것이 비즈니스 프로세스에 적합한 솔루션입니다.