Почему этот триггер изменил скорость моего запроса? - PullRequest
4 голосов
/ 14 октября 2010

Я пытался решить проблему медленного триггера, и теперь, когда я прошел методом проб и ошибок, я все еще не знаю, в чем была первоначальная проблема.

Запрос, который я выполняю, - этоследующее:

UPDATE tblA 
SET X = NULL
WHERE X IS NOT NULL AND Z = 0

Обновляется около 30 тыс. строк.

И часть триггера AFTER INSERT, UPDATE на tblA, вызывающая проблему, была следующей:

IF EXISTS(SELECT 1
          FROM inserted
          LEFT JOIN deleted ON deleted.PK = inserted.PK
          WHERE (inserted.Y IS NOT NULL AND deleted.Y IS NULL)
              OR inserted.Y <> deleted.Y
BEGIN

    -- The above condition is not met for my query so we would never get here
    INSERT INTO tblB
    (...)
    SELECT
    inserted.X,
    ...
    FROM
    inserted
    LEFT JOIN deleted ON deleted.PK = inserted.PK
    WHERE (inserted.Y IS NOT NULL AND deleted.Y IS NULL)
        OR inserted.Y <> deleted.Y

END

Я полагаю, что вышеупомянутое IF EXISTS было включено, чтобы остановить потенциальные циклические срабатывания триггеров INSERT, когда вставки фактически не происходили, но на самом деле это не проблема для tblB, так как он имеет только один триггер.

Поэтому я изменил это на следующее:

INSERT INTO tblB
(...)
SELECT
inserted.X,
...
FROM
inserted
LEFT JOIN deleted ON deleted.PK = inserted.PK
WHERE (inserted.Y IS NOT NULL AND deleted.Y IS NULL)
    OR inserted.Y <> deleted.Y

И время запроса на обновление теперь сократилось с> 1 часа до приблизительно 30 секунд.

Я ожидал, что онозаймет столько же времени.Почему это быстрее?

ОБНОВЛЕНИЕ: После проверки плана выполнения для выполнения моего запроса на обновление с медленным триггером

Проверка IF EXISTS обошлась в 0%, с73% стоимости идет на утверждение другого триггера, который вносит изменения в таблицу аудита.Само по себе это не кажется необоснованным, поскольку это утверждение довольно сложное с большим количеством объединений, но я не знаю, почему мое изменение в переписывании IF EXISTS имело какое-либо значение.Возможно, моя проверка IF EXISTS как-то мешает вставке таблицы аудита, чтобы замедлить их, но я не знаю, почему новая версия не делает то же самое, поскольку содержит тот же SELECT.[Большая часть этой стоимости была потрачена на буферизацию таблицы.]

Еще 13% стоимости запроса тратится на третий триггер, который обновляет временную метку на tblA, если конкретные значения столбца изменились.Это снова включается при вставке и удалении, плюс по табличке.Этот оператор обновления не оказал бы никакого влияния на мой запрос, так как изменения в столбце X не заслуживают обновления отметки времени.[Эта стоимость была разделена между внутренним объединением хеш-соответствия между tblA и вставленным, и обновлением кластеризованного индекса - кажется разумным.]

Чтобы добавить больше путаницы: если я отключаю триггер, это стоит 73% времени, нооставив старый триггер, упомянутый выше, без изменений, мой запрос все еще занимает много часов.Я не пробовал отключать триггер отметки времени.

Если посмотреть на план запроса при использовании быстрого триггера, соотношения практически одинаковы, но общее время чуть меньше.

Ответы [ 2 ]

1 голос
/ 20 октября 2010

Пожалуйста, изучите план выполнения и посмотрите, в чем различия между каждым прогоном.Я предполагаю, что SQL-сервер использует другой план выполнения для вашего запроса о существовании (...), чем для вставки-выбора, поскольку он не должен охватывать все столбцы в первом случае.Если есть запутанные индексы или запутанная статистика, оптимизация может запутаться и выбрать действительно плохой план.По этой причине после изучения и сохранения планов выполнения попытайтесь реорганизовать / перестроить все индексы и пересчитать статистику для этой таблицы.

С уважением, Роб

0 голосов
/ 14 октября 2010

ну, я не совсем уверен, что произошло между ними, но я могу предложить вам пару советов, чтобы ускорить его еще

первое, что я бы изменил, это:

WHERE (inserted.Y IS NOT NULL AND deleted.Y IS NULL) 

к этому:

WHERE (inserted.Y >'' AND deleted.Y IS NULL) 

IS NULL вызывает поиск по индексу, где>> 'позволяет выполнять поиск по sql и дает вам тот же набор результатов (в зависимости от того, является ли y целым, если это varchar, то вы можете изменить на> = '')

...