Подтвердить что ты не робот

Является ли @@ROWCOUNT после UPDATE надежной мерой * соответствия * строк?

Надежность @@ROWCOUNT показывает, сколько строк соответствовало предложению WHERE в UPDATE, в отличие от того, сколько из них действительно изменилось?

В документации для @@ROWCOUNT говорится:

Операторы языка манипуляции данными (DML) устанавливают значение @@ROWCOUNT в число строк , затронутых, и возвращают это значение клиенту.

(Мой акцент.)

Но если я

CREATE TABLE [Foo] ([a] INT, [b] INT)
GO
INSERT INTO [Foo] ([a], [b]) VALUES (1, 1),(1, 2),(1, 3),(2, 2)
GO
UPDATE [Foo] SET [b] = 1 WHERE [a] = 1
SELECT @@ROWCOUNT
GO

... Я вижу 3 (количество строк, соответствующих [a] = 1), а не 2 (количество строк, измененных UPDATE — в одной из трех строк уже было значение 1 для b). Это похоже на странное определение "затронутого" (не так, просто противоречит тому, как я обычно использую слово — на самом деле это очень удобно для того, что я хочу делать).

(Подобная функция MySQL ROW_COUNT, например, вернула бы 2 в этой ситуации.)

Является ли это надежное поведение, идеально документированное где-то, чего я просто не нашел? Или есть случаи с нечетными краями...

Чтобы быть ясным: Я не спрашиваю, правильный ли 3. Я спрашиваю, отвечает ли это надежный ответ, или есть крайние случаи, когда SQL Server оставляет строки, которые соответствуют, но не требуют изменений.

Обновление. Несколько человек спросили (или намекнули), какие проблемы с "надежностью" я волнуюсь. Дело в том, что они довольно туманны, но, неслучайно, тиражирование? Сделки? Разметка? Индексы, которые он может использовать, чтобы избежать поиска строк, поскольку он знает, что b уже 1, и поэтому он пропускает их?...

Обновление. Я надеялся, что кто-то с более "инсайдерским" представлением о том, как SQL Server работает, чтобы ответить на этот вопрос, но он выглядит как пример триггеров (и другие, с которыми я играл) от xacinay так близко, как мы собираемся получить. И это кажется довольно проклятым. если он ведет себя таким образом в нормальном случае, и он не вел себя так, несмотря на разделение или whatsit, как сказал кто-то, наверняка это квалифицировалось бы как ошибка. Это просто эмпирическое, а не академическое.

4b9b3361

Ответ 1

Документация для @@ROWCOUNT говорит вам правду, потому что 3 строки будут надежно затронуты, а не MySQL ROW_COUNT().

not 2 (количество строк, измененных UPDATE - один из трех строки уже имели значение 1 для b).

Для UPDATE не важно, совпадают ли новые и предыдущие значения. Он просто выполняет то, что он сказал: находит источник данных, фильтрует строки в соответствии с предоставленным условием и применяет "установленные" изменения к отфильтрованным строкам.

То, как SQL Server работает без каких-либо оговорок. MySQL может работать по-другому. Процедура подсчета строк не является частью стандарта SQL. Таким образом, вы должны смотреть, прежде чем прыгать на эти виды артефактов каждый раз, когда вы переключаетесь с одной РСУБД на другую.

Некоторые триггеры для просмотра фактического поведения обновления:

CREATE TRIGGER [dbo].[trgFooForUpd]
ON [dbo].[Foo]
FOR UPDATE 
AS begin declare @id int;
      select @id = [a] from INSERTED;
      select * from INSERTED; end;
GO
CREATE TRIGGER [dbo].[trgFooAfterUpd]
ON [dbo].[Foo]
AFTER UPDATE 
AS print 'update done for ' + cast(coalesce( @@ROWCOUNT, -1) as varchar )+'rows'

Ответ 2

Развернуть на xacinay ответ, потому что он прав.

У вас есть 3 строки, и поэтому @@ROWCOUNT является точным. SQL Server меняет все строки, он не проверяет, что на самом деле значение действительно отличается перед изменением, поскольку для выполнения команд обновления потребуется много накладных расходов. Просто подумайте, нужно ли проверять VARCHAR (MAX) на то, действительно ли значение было изменено или нет.

Самый простой способ проиллюстрировать это - фактически изменить yor UPDATE-запрос на что-то вроде этого:

UPDATE [Foo]  SET [b] = 1
OUTPUT INSERTED.b
WHERE [a] = 1

Он выведет 3 строки INSERTED, которая является таблицей "псевдо", которая содержит новые значения для данной команды update/insert. То, что значение фактически равно b = 1 в одном экземпляре, не имеет значения.

Если вы хотите, чтобы это было важно, вам нужно включить его в предложение WHERE:

UPDATE [Foo]  SET [b] = 1
WHERE [a] = 1 AND [b] <> 1
SELECT @@ROWCOUNT

В качестве альтернативы и в качестве более общего способа выполнения этой проверки вы можете создать триггер и сравнить значения/поля в таблице DELETED со значениями в таблице INSERTED и использовать это как основание для того, строка фактически "изменена".

So - 3 - точное число, так как вы обновили 3 строки, потому что 3 строки были затронуты [a] = 1

Ответ 3

Я думаю, что документация правильная, потому что независимо от того, что одна строка в вашем примере уже имела значение 1 в [b], эта строка все еще удовлетворяла критериям в предложении WHERE, поэтому значение было обновлено.

Мы можем увидеть доказательство, немного расширив ваш пример и включив столбец TIMESTAMP, как в этот SQLFiddle. После обновления TIMESTAMP для всех столбцов, которые были сопоставлены с claase WHERE, изменилось, указав, что сама строка была изменена, а не просто оценена и отброшена, потому что целевое значение соответствовало тому, что уже было.

Ответ 4

В заключение вы спрашиваете, является ли @@rowcount детерминированным. Действительно, если это не было детерминированным, вы не думаете, что увидите это в документации? Разумно предположить детерминированный. @@VERSION и @@MAX_PRECISION также не задокументированы как детерминированные, основанные на том, что вы подвергаете сомнению краевые случаи, когда они не детерминированы. Я серьезно сомневаюсь, что есть краткий случай, который он терпит неудачу, но он это делает, тогда Microsoft примет его как ошибку. Они не собираются возвращаться с @@rowcount недетерминированным - в документации явно не указано детерминированное.

Многочисленные примеры, которые "затронуты" в TSQLQLQLQLQL подсчитывают строку, установленную на одно и то же значение (она только заботится о том, где)
И у вас есть примеры того, что MSSQL фактически присваивает одинаковое значение (временная метка)
Вы утверждаете, что SQL может заботиться о том, как я могу это сделать. Я знаю, что нет граничного случая, который делает Потому что это не разумное поведение
Любая программа должна производить последовательный вывод
Заказ без сортировки не гарантируется, но строки одинаковы - это специально документировано Microsoft и SQL как недетерминированные
Если @@rowcount был недетерминирован, то я полагаю, что Microsoft будет документировать, что Разумно предположить, что @@rowcount является детерминированным
С# и Java не всегда имеют одинаковое поведение
Это не повод для меня подозревать, что С# и Java не надежны

Посмотрите план запроса в MSSQL
Нет предиката на [a]
На [b]

имеется предикат,

Если вы измените запрос на

UPDATE [Foo] SET [b] = 1 WHERE [a] <> 1 and [b] = 1;

Затем вы увидите предикаты как для [a], так и [b]

Оптимизатор запросов решит, как наиболее эффективно обрабатывать запрос, который он не собирается изменять. Представление предиката в [b] в первом запросе меняет запрос.
Правильная база данных просто этого не делает.

Я очень подозреваю, что в MySQL, если вы посмотрите на план запроса, в первом запросе будет предикат [a].

Вместо того, чтобы требовать доказательства, которые являются надежными, создайте кромку края, которая доказывает, что она не надежна.
Если вы можете создать ситуацию, это не является надежным. Я отправляю Microsoft, чтобы принять его как ошибку.

Что такое бизнес-пример? Если у вас есть бизнес-пример, значение должно быть обновлено с одинаковым значением, тогда по определению у вас есть что испытать.
Единственными примерами, которые я могу сделать, являются timestamp или trigger.
Если у вас есть настоящая потребность в том, чтобы обновление было таким же, чтобы иметь место, тогда вам есть что измерить.
У вас есть доказательства того, что значение не обновляется до того же значения?
Если вы все еще не доверяете этому, оберните его в транзакцию.

Если вам не требуется обновление до того же значения, то почему бы просто не добавить [b] < > 1. Это более эффективно.

SO - для конкретного вопроса программирования.
Что такое вопрос программирования?
Докажите, что MSSQL надежна, это не вопрос программирования.