트리거는 매번 컴파일됩니까?


22

CPU 사용률이 높은 서버의 문제를 해결하고 있습니다. 쿼리가 실제로 발생하지 않았 음을 확인한 후 컴파일을 조사하기 시작했습니다.

성능 모니터에 초당 50 회 미만의 컴파일 및 초당 15 회 미만의 재 컴파일이 표시됩니다.

컴파일을 찾는 XE 세션을 실행하면 초당 수천 개의 컴파일이 표시됩니다.

이 시스템은 트리거를 사용하여 변경 사항을 감사합니다. 대부분의 컴파일은 트리거로 인한 것입니다. 트리거는 sys.dm_tran_active_transactions를 참조합니다.

첫 번째 생각은 트리거에서 DMV를 참조하면 매번 컴파일되거나이 특정 DMV만으로 인해 발생하는 것으로 생각했습니다. 그래서 저는 그 이론을 테스트하기 시작했습니다. 매번 컴파일하지만 DMV를 참조하지 않고 대신 값을 하드 코딩 할 때 트리거 될 때마다 트리거가 컴파일되는지 확인하지 않았습니다. 트리거 될 때마다 여전히 컴파일 중이었습니다. 트리거를 삭제하면 컴파일이 중지됩니다.

  1. XE 세션에서 sqlserver.query_pre_execution_showplan을 사용하여 컴파일을 추적합니다. 왜 그와 PerfMon 카운터 사이에 불일치가 있습니까?
  2. 트리거가 실행될 때마다 컴파일 이벤트가 발생하는 것이 정상입니까?

재현 스크립트 :

CREATE TABLE t1 (transaction_id int, Column2 varchar(100));
CREATE TABLE t2 (Column1 varchar(max), Column2 varchar(100));
GO

CREATE TRIGGER t2_ins
ON t2
AFTER INSERT
AS

INSERT INTO t1
SELECT (SELECT TOP 1 transaction_id FROM sys.dm_tran_active_transactions), Column2
FROM inserted;
GO

--Both of these show compilation events
INSERT INTO t2 VALUES ('row1', 'value1');
INSERT INTO t2 VALUES ('row2', 'value2');
GO

ALTER TRIGGER t2_ins
ON t2
AFTER INSERT
AS

INSERT INTO t1
SELECT 1000, Column2
FROM inserted;
GO

--Both of these show compilation events
INSERT INTO t2 VALUES ('row3', 'value3');
INSERT INTO t2 VALUES ('row4', 'value4');

DROP TRIGGER t2_ins;

--These do not show compilation events
INSERT INTO t2 VALUES ('row5', 'value5');
INSERT INTO t2 VALUES ('row6', 'value6');

DROP TABLE t1, t2;

답변:


20

사용중인 XE 이벤트로 인해 트리거가 실제로 모든 실행을 컴파일하는 것으로 잘못 인식하게됩니다. 설명이 비슷하지만 중요한 단어가 다른 두 가지 확장 이벤트 query_pre_execution_showplan 및 query_post_compilation_showplan이 있습니다.

query_pre_execution_showplan

SQL 문이 컴파일 된 후에 발생합니다. 이 이벤트는 쿼리가 최적화 될 때 생성되는 예상 쿼리 계획의 XML 표현을 반환합니다 . 이 이벤트를 사용하면 상당한 성능 오버 헤드가 발생할 수 있으므로 짧은 시간 동안 특정 문제를 해결하거나 모니터링 할 때만 사용해야합니다.

query_post_compilation_showplan

SQL 문이 컴파일 된 후에 발생합니다. 이 이벤트는 쿼리가 컴파일 될 때 생성되는 예상 쿼리 계획의 XML 표현을 반환합니다 . 이 이벤트를 사용하면 상당한 성능 오버 헤드가 발생할 수 있으므로 짧은 시간 동안 특정 문제를 해결하거나 모니터링 할 때만 사용해야합니다.

이벤트는 설명에서 정확히 동일하지 않으며 repro를 사용한 추가 테스트와 다른 시간에 발생합니다. 훨씬 더 큰 이벤트 세션 정의를 사용하면 컴파일이 실제로 발생하는 위치를 쉽게 확인할 수 있습니다.

여기에 이미지 설명을 입력하십시오

여기서 녹색 상자에서 준비된 계획이 자동 매개 변수화됨에 따라 삽입 명령문에 대해 첫 번째 컴파일이 발생하는 것을 볼 수 있습니다. 트리거는 빨간색 상자에 컴파일되고 sp_cache_insert 이벤트에 표시된대로 계획이 캐시에 삽입됩니다. 주황색 상자에서 트리거 실행은 캐시 적중을 가져오고 배치의 두 번째 INSERT 문에 대한 트리거 계획을 재사용하므로 INSERT 명령의 모든 실행을 컴파일하지는 않으며 sp_cache_hit 이벤트에서 볼 수 있듯이 계획이 재사용됩니다. 방아쇠를 위해.

첫 번째 실행 후 두 개의 INSERT 문을 개별적으로 다시 실행하면 아래 이벤트와 같이 트리거가 다시 컴파일되지 않습니다.

여기에 이미지 설명을 입력하십시오

여기서 첫 번째 명령문은 준비된 자동 매개 변수화 된 버전의 명령문에 대해 캐시 적중을 발견했지만 제출 된 임시 배치에 대해서는 누락되었습니다. 트리거는 캐시 적중을 가져오고 빨간색 이벤트 블록에 표시된대로 다시 컴파일되지 않습니다. 녹색 이벤트 블록은 별도의 배치로 실행되는 두 번째 INSERT 문에 대해이 동작을 반복합니다. 그러나 모든 경우에 여전히 query_pre_execution_showplan 이벤트 발사를 볼 수있는 내가 할 수있는 유일한되고의 차이에 속성 최적화컴파일 이벤트 설명에 있지만, 사건이 일련의 그림과 같이 트리거는 모든 실행을 위해 컴파일되지 않습니다.


첫 번째 스크린 샷을 보면 캐시되지 않은 sql_batch_statistics 이벤트가 콜렉션에 있지만 캐시가 지워지고 INSERT에 대한 자동 매개 변수화 된 계획이 계획 캐시에없는 경우 SQL 배치의 첫 번째 실행에 대해서만 실행됩니다. 그 후 uncached_sql_batch_statistics 이벤트가 다시 발생하지 않습니다.
Jonathan Kehayias 2012 년

query_post_compilation_showplan은 트리거에 대한 몇 가지 컴파일을 보여 주었지만 다른 이벤트에서 보았던 엄청난 양은 아닙니다. 우리는 query_post_compilation_showplan과 함께 흥미로운 너겟을 발견했습니다. 정보 주셔서 감사합니다, 조나단!
Tara Kizer 2016 년

13

아니요. 트리거가 항상 다시 컴파일되는 것은 아닙니다. 그러나 간단한 쿼리 문은 계획을 캐시하지 않으므로 항상 다시 컴파일됩니다.

삽입 또는 삭제 된 행 수가 크게 변경되면 트리거가 다시 컴파일됩니다. 참조 : https://technet.microsoft.com/en-us/library/ms181055.aspx

XEvents에서 동일한 지 여부는 알지 못하지만 SQL Trace에서 재 컴파일에는 재 컴파일 된 이유를 알려주는 이벤트 서브 클래스가 있습니다. 위의 동일한 링크에 설명되어 있습니다.


1
우리는 재 컴파일보다는 컴파일을보고있었습니다. 내일 서버를 살펴보고 간단한 쿼리 문 때문인지 또는 행 수 때문인지 확인합니다. 감사!
타라 키저
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.