Является ли обновление / выбор одного столбца в одной строке атома c и безопасным на SQL Сервере? - PullRequest
0 голосов
/ 25 апреля 2020

Я бы хотел использовать следующий оператор для обновления столбца одной строки:

UPDATE Test SET Column1 = Column1 & ~2 WHERE Id = 1

Кажется, что вышеприведенное работает. Это безопасно на SQL сервере? Я помню, как читал о возможных взаимоблокировках при использовании аналогичных характеристик в СУБД, отличной от SQL (думаю, это было связано с PostgreSQL).

Пример таблицы и соответствующих хранимых процедур:

CREATE TABLE Test (Id int IDENTITY(1,1) NOT NULL, Column1 int NOT NULL, CONSTRAINT PK_Test PRIMARY KEY (Id ASC))
GO
INSERT INTO Test (Column1) Values(255) 
GO
-- this will always affect a single row only
UPDATE Test SET Column1 = Column1 & ~2 WHERE Id = 1

Ответы [ 2 ]

1 голос
/ 26 апреля 2020

Для структуры таблицы, которую вы показали, и UPDATE, и SELECT являются автономными транзакциями и могут использовать поиск кластеризованных индексов для выполнения своей работы без необходимости читать ненужные строки и устанавливать ненужные блокировки, так что меня это не особенно беспокоит. о взаимоблокировках с этой процедурой.

Меня больше беспокоит тот факт, что у вас нет UPDATE и SELECT внутри одной транзакции. Таким образом, блокировка X для строки будет снята, как только оператор обновления завершится, и другая транзакция сможет изменить значение столбца (или даже удалить всю строку) до выполнения SELECT.

Если вы выполняете оба оператора внутри одной и той же транзакции, я все равно не буду беспокоиться о потенциальной взаимоблокировке, поскольку первичная блокировка берется первой (было бы другое дело, если бы SELECT произошло до UPDATE)

Вы также можете решить проблему параллелизма, полностью избавившись от SELECT и используя предложение OUTPUT для возврата клиенту значения после обновления.

UPDATE Test SET Column1 = Column1 & ~2 
OUTPUT INSERTED.Column1
WHERE Id = 1
0 голосов
/ 25 апреля 2020

Что вы подразумеваете под "это безопасно"?

Ваш id является уникальным идентификатором для каждой строки. Я настоятельно рекомендую вам объявить это как primary key. Но у вас должен быть индекс для столбца.

Без индекса у вас есть потенциальная проблема с производительностью (и взаимными блокировками), поскольку SQL Сервер должен сканировать всю таблицу. Но с соответствующим объявлением primary key (или другим индексом) вы обновляете только одну строку в одной таблице. Если у вас нет триггеров на столе, то не так много всего, что может помешать другим транзакциям.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...