Обновление столбца с его текущим значением

#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 просто не меняли значения, но в тестовой среде это не имело значения. После переноса приложения в рабочую среду с помощью зеркального отображения нам бы очень хотелось получить подсказку «только измененное значение». Чтение исходного значения и его проверка не занимают времени по сравнению с записью