#sql-server #optimization
#sql-server #оптимизация
Вопрос:
У меня есть сохраненная процедура, которая должна условно обновлять кучу полей в одной таблице. Условно, потому что для каждого поля я также передаю «грязный» флаг, и поле должно обновляться, только если флаг установлен в 1.
Итак, я собираюсь сделать следующее:
create proc update
@field1 nvarchar(1000), @field1Dirty bit, ...other fields...
as
begin
update mytable
set field1 = case when @field1dirty = 1 then @field1 else field1 end,
... same for other fields
end
go
Вопрос — достаточно ли умен SQL Server (2008), чтобы физически не обновлять поле, если ему присвоено собственное значение, например, в случае, если @field1dirty = 0?
Ответ №1:
Question - is SQL Server (2008) smart enough to not physically update
поле, если ему было присвоено собственное
значение, как в случае, если @field1dirty =
0?
Нет, вы должны добавить предложение where, в котором говорится … where field <> the value you are updating to
.
На первый взгляд это не кажется чем-то особенным, но на самом деле это может привести к огромным накладным расходам. В качестве одного из примеров подумайте о триггерах. Если это обновит каждое поле в таблице, этот триггер сработает для каждой строки. БЛИН, столько ненужного выполнения кода, особенно если этот код, скажем, перемещает обновленные строки в таблицу ведения журнала. Я уверен, что вы поняли идею.
Помните, что при обновлении поля оно просто принимает то же значение, что и раньше. На самом деле хорошо, что это происходит, потому что это означает, что вы все еще можете считать поле измененным (например, временная метка и т.д.). Если бы он не думал, что обновление поля до того же значения изменяет строку, вы бы не знали, пытался ли кто-то непреднамеренно (или намеренно) изменить данные.
Обновление из-за комментариев: ссылка на функцию coalesce
Пример: Для обработки значений параметра null в вашей хранимой процедуре
Update Table SET My_Field = COALESCE(@Variable, My_Field)
Это не позволяет обойти то, о чем я говорил ранее, когда поле обновляется до того же значения, но это позволяет вам проверить параметр и условно обновить поле.
Комментарии:
1. Хороший момент, но я очень надеюсь, что люди не везде устанавливают триггеры!
2. Я тоже, но это был самый простой пример, который я смог придумать на лету и который донес суть.
3. Не удается добавить предложение where, потому что на самом деле в одном обновлении есть несколько полей — как я уже сказал, показанный случай был самым простым.
4. Думаю, тогда мне придется перейти на динамический sql
5. @Andrey — вы все еще можете использовать,
WHERE
просто разделите их наOR
. SQL Server записывает целую строку за раз, поэтому, если выполняется КАКОЕ-либо условие, он в любом случае перепишет всю строку, и ваша производительность не пострадает.
Ответ №2:
SQL не проверяет значение перед записью в него. Он все равно перезапишет его.
Ответ №3:
SQL Server выполнит обновление. Строка будет обновляться как целая строка, поэтому, если один столбец в строке имеет FieldxDirty = 1, обновление требуется в любом случае. В предложении SET оптимизация не достигается.
Ответ @Kevin’s поможет больше, чем оптимизация предложения SET .
Ответ №4:
Извините, что пришел сюда с мнением, но мне больше некуда писать 🙂 Должна быть, по крайней мере, своего рода «подсказка», позволяющая указать оператору UPDATE, чтобы он обычно НЕ обновлялся до того же значения.
Есть по крайней мере 2 причины, о которых я могу думать: 1. значение для обновления может быть сложным выражением, и повторное выражение его в предложении WHERE является пустой тратой времени выполнения (не говоря уже о поддержании изменений выражения). Подумайте также о нулевых значениях! Например. UPDATE X SET A = B ГДЕ ISNULL(A,») <> ISNULL(B,»)
2-й: у нас есть сценарий синхронизированного зеркального отображения, в котором сервер «резервного копирования» физически размещен в другой части города. Это означает, что запись на диск выполняется первой, когда резервный сервер выполнил запись. Существует огромная разница во времени между записью и пропуском записи. Когда разработчики создавали приложение, они работали в тестовой среде без зеркального отображения. Большинство инструкций UPDATE просто не меняли значения, но в тестовой среде это не имело значения. После переноса приложения в рабочую среду с помощью зеркального отображения нам бы очень хотелось получить подсказку «только измененное значение». Чтение исходного значения и его проверка не занимают времени по сравнению с записью