두 번째 INSERT
문장 이 왜 첫 번째 문장보다 ~ 5 배 느린가요?
생성 된 로그 데이터 양에서 두 번째는 최소 로깅에 적합하지 않다고 생각합니다. 그러나 Data Loading Performance Guide 의 문서에는 두 삽입물 모두를 최소한으로 기록 할 수 있어야합니다. 최소 로깅이 주요 성능 차이라면 왜 두 번째 쿼리가 최소 로깅에 적합하지 않습니까? 상황을 개선하기 위해 무엇을 할 수 있습니까?
쿼리 # 1 : INSERT ... WITH (TABLOCK)를 사용하여 5MM 행 삽입
5MM 행을 힙에 삽입하는 다음 쿼리를 고려하십시오. 이 쿼리는에서 보고 한대로 트랜잭션 로그 데이터를 실행 1 second
하고 생성 64MB
합니다 sys.dm_tran_database_transactions
.
CREATE TABLE dbo.minimalLoggingTest (n INT NOT NULL)
GO
INSERT INTO dbo.minimalLoggingTest WITH (TABLOCK) (n)
SELECT n
-- Any table/view/sub-query that correctly estimates that it will generate 5MM rows
FROM dbo.fiveMillionNumbers
-- Provides greater consistency on my laptop, where other processes are running
OPTION (MAXDOP 1)
GO
쿼리 # 2 : 동일한 데이터를 삽입하지만 SQL은 행 수를 과소 평가합니다
이제 정확히 동일한 데이터에서 작동하지만 SELECT
카디널리티 추정치가 너무 낮은 테이블 (또는 실제 생산 사례에서 많은 조인이있는 복잡한 명령문) 에서 발생하는이 매우 유사한 쿼리를 고려하십시오 . 이 쿼리 는 트랜잭션 로그 데이터를 실행 5.5 seconds
하고 생성 461MB
합니다.
CREATE TABLE dbo.minimalLoggingTest (n INT NOT NULL)
GO
INSERT INTO dbo.minimalLoggingTest WITH (TABLOCK) (n)
SELECT n
-- Any table/view/sub-query that produces 5MM rows but SQL estimates just 1000 rows
FROM dbo.fiveMillionNumbersBadEstimate
-- Provides greater consistency on my laptop, where other processes are running
OPTION (MAXDOP 1)
GO
전체 스크립트
테스트 데이터를 생성하고 이러한 시나리오 중 하나를 실행하는 전체 스크립트 세트는 이 Pastebin 을 참조하십시오 . SIMPLE
복구 모델 에있는 데이터베이스를 사용해야합니다 .
사업 상황
우리는 수백만 행의 데이터를 반쯤 자주 이동하고 있으므로 실행 시간과 디스크 I / O로드 측면에서 이러한 작업을 최대한 효율적으로 수행하는 것이 중요합니다. 우리는 처음에 힙 테이블을 생성하고 사용 INSERT...WITH (TABLOCK)
하는 것이 좋은 방법 이라는 인상을 받았지만 실제 생산 시나리오에서 위에서 설명한 상황을 관찰했다는 확신을 가지지 못했습니다 (더 복잡한 쿼리는 아니지만) 여기에 단순화 된 버전).
SELECT
결과 집합을 생성하는 많은 조인 이있는 복잡한 문이INSERT
있습니다. 이 조인은 최종 테이블 삽입 연산자 (잘못된UPDATE STATISTICS
호출을 통해 repro 스크립트에서 시뮬레이션)에 대한 카디널리티 추정치가 좋지 않으므로UPDATE STATISTICS
문제를 해결하기 위해 명령을 실행하는 것만 큼 간단하지 않습니다 . Cardinality Estimator가 이해하기 쉽도록 쿼리를 단순화하는 것이 좋은 접근 방법이지만, 복잡한 비즈니스 로직을 구현하는 것은 쉬운 일이 아니라는 점에 동의합니다.