Чи спрацьовують тригери щоразу?


22

Ми усуваємо проблеми з сервером, який використовує центральний процесор. Виявивши, що запити насправді не викликають цього, ми почали розглядати компіляції.

Монітор продуктивності показує менше 50 компіляцій в секунду і менше 15 репіляцій / сек.

Після запуску сеансу XE, який шукає компіляції, ми бачимо тисячі компіляцій в секунду.

Ця система використовує тригери для аудиту змін. Більшість компіляцій відбувається через тригери. Тригери посилаються на sys.dm_tran_active_transaction.

Наша перша думка полягала в тому, що, можливо, посилання DMV в тригер спричинить його компіляцію кожного разу, або, можливо, саме цей специфічний DMV спричинить його. Тому я почав тестувати цю теорію. Вона компілюється кожен раз, але я не перевіряв, чи тригер збирає кожен раз, коли він спрацьовує, коли він не посилається на DMV, а замість цього жорсткий код. Вона все ще збиралася щоразу, коли вона спрацьовувала. Відхилення тригера зупиняє компіляцію.

  1. Ми використовуємо sqlserver.query_pre_execution_showplan у сеансі XE для відстеження компіляцій. Чому існує розбіжність між цим та лічильником PerfMon?
  2. Це нормально, що ви отримуєте подію компіляції щоразу, коли запускається тригер?

Сценарій 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;

Відповіді:


20

Подія XE, що використовується, приводить вас неправильно до думки, що тригер насправді компілює кожне виконання. Є два розширені події query_pre_execution_showplan та query_post_compilation_showplan, які мають подібні описи, але відрізняються одним важливим словом:

query_pre_execution_showplan

Виникає після компіляції оператора SQL. Ця подія повертає XML-представлення передбачуваного плану запитів, що формується при оптимізації запиту . Використання цієї події може мати значну ефективність роботи, тому її слід використовувати лише під час усунення несправностей або моніторингу конкретних проблем на короткий проміжок часу.

query_post_compilation_showplan

Виникає після компіляції оператора SQL. Ця подія повертає XML - уявлення оціненого плану запиту , який генерується , коли запит складено . Використання цієї події може мати значну ефективність роботи, тому її слід використовувати лише під час усунення несправностей або моніторингу конкретних проблем на короткий проміжок часу.

Події не є абсолютно однаковими за описом і відбуваються в різний час від подальшого тестування за допомогою вашої репро. За допомогою значно більшого визначення сеансу подій легко зрозуміти, де компіляції насправді відбуваються.

введіть тут опис зображення

Тут ви можете побачити першу компіляцію для операторів вставки, оскільки підготовлені плани автоматично параметризуються в зеленому полі. Тригер складається в червоному полі і план вставляється в кеш, як показано подією sp_cache_insert. Потім у помаранчевому полі виконання тригера отримує кеш-хіт і повторно використовує план тригера для другого оператора INSERT у пакеті, тому воно не компілює кожне виконання команди INSERT, і план повторно використовується, як ви можете бачити з подією sp_cache_hit для тригера.

Якщо ми знову запустимо два оператора INSERT окремо після першого виконання, тригер знову не компілюється, як показано в подіях нижче:

введіть тут опис зображення

Тут перший випадок зустрічається з посиланням на кеш для підготовленої автоматичної параметризованої версії оператора в кеші, але пропущений пакет adhoc, який був поданий. Тригер отримує звернення до кешу і не збирається знову, як показано на червоному блоці подій. Зелений блок подій повторює цю поведінку для другого оператора INSERT, запущеного як окремий пакет. Однак у будь-якому випадку ви все ще бачите запит події query_pre_execution_showplan, який я можу лише віднести до різниці в оптимізації проти компіляції в описі події, але тригер не компілюється для кожного виконання, як показано цією низкою подій.


Якщо ви подивитесь на перший скріншот, подія не кешована sql_batch_statistics знаходиться в колекції, але тільки запускається для першого виконання пакету sql, коли кеш очищений, а автоматичний параметризований план для INSERT не знаходиться в кеші плану. Після цього подія uncached_sql_batch_statistics знову не спрацьовує.
Джонатан Кехайяс

У Query_post_compilation_showplan було показано лише декілька збірок на тригерах, але не величезна кількість, яку ми спостерігали під час іншої події. Ми знайшли цікаві самородки з query_post_compilation_showplan. Дякую за інформацію, Джонатане!
Тара Кізер

13

Ні. Тригери не завжди перекомпілюються. Однак, прості заяви запиту не мають кешованих планів і тому завжди будуть перекомпільовані.

Тригери дійсно перекомпілюються, якщо кількість рядків у вставлених або видалених істотно зміниться. Дивіться: https://technet.microsoft.com/en-us/library/ms181055.aspx

Я не знаю, чи є вони однакові в XEvents, але в SQL Trace рекомпіляція має підклас подій, який говорить вам, чому вона була перекомпільована. Це пояснено у тому ж посиланні, що вище.


1
Ми розглядали компіляції, а не рекомпіляції. Ми завтра подивимось на сервер і перевіримо, чи це пов’язано з простою заявою запиту чи це через кількість рядків. Спасибі!
Тара Кізер
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.