Rozwiązujemy problemy z serwerem o wysokim wykorzystaniu procesora. Po stwierdzeniu, że zapytania tak naprawdę nie były przyczyną, zaczęliśmy szukać kompilacji.
Monitor wydajności pokazuje mniej niż 50 kompilacji / sek. I mniej niż 15 rekompilacji / sek.
Po uruchomieniu sesji XE w poszukiwaniu kompilacji widzimy tysiące kompilacji na sekundę.
Ten system używa wyzwalaczy do kontrolowania zmian. Większość kompilacji wynika z wyzwalaczy. Wyzwalacze odwołują się do sys.dm_tran_active_transactions.
Naszą pierwszą myślą było, że może odwołanie się do DMV w wyzwalaczu spowoduje, że kompiluje się za każdym razem, a może właśnie ten konkretny DMV to spowoduje. Więc zacząłem testować tę teorię. Kompiluje się za każdym razem, ale nie sprawdziłem, czy wyzwalacz kompiluje się za każdym razem, gdy jest wyzwalany, gdy nie odwołuje się do DMV i zamiast tego zapisuje wartość na stałe. Wciąż się kompilował za każdym razem, gdy był uruchamiany. Upuszczenie wyzwalacza powoduje zatrzymanie kompilacji.
- Używamy narzędzia sqlserver.query_pre_execution_showplan w sesji XE do śledzenia kompilacji. Dlaczego istnieje rozbieżność między tym a licznikiem PerfMon?
- Czy to normalne, że zdarzenie kompilacji występuje za każdym razem, gdy uruchamiany jest wyzwalacz?
Skrypt repro:
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;
źródło
Nie. Wyzwalacze nie zawsze są rekompilowane. Proste instrukcje zapytań nie pobierają jednak swoich planów i dlatego zawsze będą ponownie kompilowane.
Wyzwalacze są ponownie kompilowane, jeśli liczba wierszy we wstawionych lub usuniętych zmianach ulegnie znaczącej zmianie. Zobacz: https://technet.microsoft.com/en-us/library/ms181055.aspx
Nie wiem, czy mają to samo w XEventach, ale w SQL Trace rekompilacja ma podklasę zdarzeń, która mówi ci, dlaczego została zrekompilowana. Wyjaśnia to ten sam link powyżej.
źródło