Неприятный побочный эффект OUTPUT
Пересказ статьи Erik Darling. An Unfortunate Side Effect Of OUTPUT
Время от времени я встречаю людей, которые используют OUTPUT для аудита модификаций чаще всего потому, что "триггеры - это плохо" или "триггеры медленные".
Хорошо, иногда это действительно так. Но использование OUTPUT тоже может быть неудачным решением.
Давайте посмотрим, как это может быть.
Скажем, у нас есть таблица, которую мы используем для отслеживания лучших результатов пользователей по вопросам.
Для тестирования процесса давайте добавим одного пользователя в таблицу:
Чтобы усугубить проблему, я не собираюсь создавать тут никаких полезных индексов. Это хороший симулятор виртуальной реальности, поскольку я видел ваши индексы.
Относящаяся к проблеме часть плана запроса представляет собой сканирование таблицы Posts:
Выполнение параллельно и занимает 1,8 секунд.
Давайте теперь добавим предложение OUTPUT.
Я собираюсь проигнорировать вставку вывода в какую-либо структуру, поскольку хочу, чтобы вы поняли, что место вставки не имеет значения.
Относящаяся к делу часть плана теперь выглядит так:
Мы потеряли параллелизм, и изучение свойств оператора Insert говорит нам почему:
Мы получили Non Parallel Plan Reason (причина непараллельного плана). Почему нет пробелов? Я не знаю.
Почему нельзя это выполнить параллельно? Я тоже не знаю.
Если мы создадим минимальный триггер на таблице, то сможем увидеть, какие накладные расходы это дает.
Давайте вернемся к оригинальному оператору Insert без Output! Нас интересуют два момента:
Ответы в основном также положительные. План вставки по-прежнему может использовать параллелизм.
Я не буду вставлять сюда картинку, вы можете прокрутить экран вверх.
Хотя выборка из таблицы Inserted в триггере не идет параллельно, не это, похоже, ограничивает параллелизм всего плана. Видимо, чтения из таблицы Inserted не могут использовать параллелизм (типа табличной переменной в MSTVF).
Давайте немного модифицируем триггер:
Вот план запроса:
Чтение из Inserted является последовательным, однако остальная часть плана полностью охватывает параллелизм.
При хорошо настроенной рабочей нагрузке вы можете не заметить каких-либо особых издержек при использовании OUTPUT для аудита определенных действий.
Конечно, если вы используете их вместе с большими вставками, и эти большие вставки работают дольше, чем хотелось бы, возможно, пора посмотреть, сколько времени они занимают без предложения OUTPUT. Вполне возможно, что использование триггера вызовет меньше проблем с производительностью.
Появление процесса
Скажем, у нас есть таблица, которую мы используем для отслеживания лучших результатов пользователей по вопросам.
CREATE TABLE dbo.HighQuestionScores
(
Id INT PRIMARY KEY CLUSTERED,
DisplayName NVARCHAR(40) NOT NULL,
Score BIGINT NOT NULL
);
Для тестирования процесса давайте добавим одного пользователя в таблицу:
INSERT dbo.HighQuestionScores WITH (TABLOCK)
(Id, DisplayName, Score)
SELECT u.Id, u.DisplayName, p.Score
FROM dbo.Users AS u
JOIN
(
SELECT p.OwnerUserId,
MAX(p.Score) AS Score
FROM dbo.Posts AS p
WHERE p.PostTypeId = 1
GROUP BY p.OwnerUserId
) AS p ON p.OwnerUserId = u.Id
WHERE u.Id = 22656;
Чтобы усугубить проблему, я не собираюсь создавать тут никаких полезных индексов. Это хороший симулятор виртуальной реальности, поскольку я видел ваши индексы.
Относящаяся к проблеме часть плана запроса представляет собой сканирование таблицы Posts:
Выполнение параллельно и занимает 1,8 секунд.
Аудит
Давайте теперь добавим предложение OUTPUT.
Я собираюсь проигнорировать вставку вывода в какую-либо структуру, поскольку хочу, чтобы вы поняли, что место вставки не имеет значения.
INSERT dbo.HighQuestionScores WITH (TABLOCK)
(Id, DisplayName, Score)
OUTPUT Inserted.Id,
Inserted.DisplayName,
Inserted.Score
SELECT u.Id, u.DisplayName, p.Score
FROM dbo.Users AS u
JOIN
(
SELECT p.OwnerUserId, MAX(p.Score) AS Score
FROM dbo.Posts AS p
WHERE p.PostTypeId = 1
GROUP BY p.OwnerUserId
) AS p ON p.OwnerUserId = u.Id
WHERE u.Id = 22656;
Относящаяся к делу часть плана теперь выглядит так:
Мы потеряли параллелизм, и изучение свойств оператора Insert говорит нам почему:
Мы получили Non Parallel Plan Reason (причина непараллельного плана). Почему нет пробелов? Я не знаю.
Почему нельзя это выполнить параллельно? Я тоже не знаю.
Как насчет триггеров?
Если мы создадим минимальный триггер на таблице, то сможем увидеть, какие накладные расходы это дает.
CREATE OR ALTER TRIGGER dbo.hqs_insert ON dbo.HighQuestionScores
AFTER INSERT
AS
BEGIN
SET NOCOUNT ON;
SELECT Inserted.Id,
Inserted.DisplayName,
Inserted.Score
FROM Inserted;
END
Давайте вернемся к оригинальному оператору Insert без Output! Нас интересуют два момента:
- Остается ли параллельная часть плана вставки?
- Есть ли какое-либо ограничение на параллелизм с виртуальными таблицами Inserted (и, по аналогии, с Deleted)?
Ответы в основном также положительные. План вставки по-прежнему может использовать параллелизм.
Я не буду вставлять сюда картинку, вы можете прокрутить экран вверх.
Хотя выборка из таблицы Inserted в триггере не идет параллельно, не это, похоже, ограничивает параллелизм всего плана. Видимо, чтения из таблицы Inserted не могут использовать параллелизм (типа табличной переменной в MSTVF).
Давайте немного модифицируем триггер:
TRUNCATE TABLE dbo.HighQuestionScores;
INSERT dbo.HighQuestionScores WITH (TABLOCK)
(Id, DisplayName, Score)
SELECT u.Id, u.DisplayName, p.Score
FROM dbo.Users AS u
JOIN
(
SELECT p.OwnerUserId, MAX(p.Score) AS Score
FROM dbo.Posts AS p
WHERE p.PostTypeId = 1
GROUP BY p.OwnerUserId
) AS p ON p.OwnerUserId = u.Id
WHERE u.Id < 500000;
Вот план запроса:
Чтение из Inserted является последовательным, однако остальная часть плана полностью охватывает параллелизм.
Заключение
При хорошо настроенной рабочей нагрузке вы можете не заметить каких-либо особых издержек при использовании OUTPUT для аудита определенных действий.
Конечно, если вы используете их вместе с большими вставками, и эти большие вставки работают дольше, чем хотелось бы, возможно, пора посмотреть, сколько времени они занимают без предложения OUTPUT. Вполне возможно, что использование триггера вызовет меньше проблем с производительностью.
Обратные ссылки
Автор не разрешил комментировать эту запись
Комментарии
Показывать комментарии Как список | Древовидной структурой