У меня есть ситуация, когда приложение «издатель» по существу поддерживает модель представления в актуальном состоянии, запрашивая ОЧЕНЬ сложное представление и затем объединяя результаты в денормализованную таблицу модели представления, используя отдельные операции вставки, обновления и удаления.
Теперь, когда мы обновились до SQL 2008, я подумал, что сейчас самое время обновить их с помощью оператора SQL MERGE. Однако после написания запроса стоимость поддерева оператора MERGE составляет 1214,54! При старом способе сумма вставки / обновления / удаления составила всего 0,104 !!
Я не могу понять, как более простой способ описания одной и той же точной операции мог бы быть настолько круче. Возможно, вы видите ошибку моего пути, где я не могу.
Некоторые статистические данные в таблице: в ней содержится 1,9 миллиона строк, и каждая операция MERGE вставляет, обновляет или удаляет более 100 из них. В моем тестовом случае затронуто только 1.
-- This table variable has the EXACT same structure as the published table
-- Yes, I've tried a temp table instead of a table variable, and it makes no difference
declare @tSource table
(
Key1 uniqueidentifier NOT NULL,
Key2 int NOT NULL,
Data1 datetime NOT NULL,
Data2 datetime,
Data3 varchar(255) NOT NULL,
PRIMARY KEY
(
Key1,
Key2
)
)
-- Fill the temp table with the desired current state of the view model, for
-- only those rows affected by @Key1. I'm not really concerned about the
-- performance of this. The result of this; it's already good. This results
-- in very few rows in the table var, in fact, only 1 in my test case
insert into @tSource
select *
from vw_Source_View with (nolock)
where Key1 = @Key1
-- Now it's time to merge @tSource into TargetTable
;MERGE TargetTable as T
USING tSource S
on S.Key1 = T.Key1 and S.Key2 = T.Key2
-- Only update if the Data columns do not match
WHEN MATCHED AND T.Data1 <> S.Data1 OR T.Data2 <> S.Data2 OR T.Data3 <> S.Data3 THEN
UPDATE SET
T.Data1 = S.Data1,
T.Data2 = S.Data2,
T.Data3 = S.Data3
-- Insert when missing in the target
WHEN NOT MATCHED BY TARGET THEN
INSERT (Key1, Key2, Data1, Data2, Data3)
VALUES (Key1, Key2, Data1, Data2, Data3)
-- Delete when missing in the source, being careful not to delete the REST
-- of the table by applying the T.Key1 = @id condition
WHEN NOT MATCHED BY SOURCE AND T.Key1 = @id THEN
DELETE
;
Так, как это достигает 1200 поддеревьев? Доступ к данным из самих таблиц представляется достаточно эффективным. На самом деле 87% стоимости MERGE, похоже, приходится на операцию сортировки в конце цепочки:
MERGE (0%) <- обновление индекса (12%) <- сортировка (87%) <- (...) </p>
И этот сорт имеет 0 строк, входящих и выходящих из него. Почему для сортировки 0 строк требуется 87% ресурсов?
UPDATE
Я разместил фактический (не оцененный) план выполнения только для операции MERGE в Gist.