Гарантируется ли выполнение SQL-запросов атомарно при использовании UNION? - PullRequest
8 голосов
/ 08 апреля 2011

Я выдаю один SQL-запрос, состоящий из нескольких SELECT, сгруппированных с использованием UNION:

SELECT *
FROM   employee 
       LEFT JOIN department 
          ON employee.DepartmentID = department.DepartmentID
UNION
SELECT *
FROM   employee
       RIGHT JOIN department
          ON employee.DepartmentID = department.DepartmentID;

Если я выполняю этот запрос в READ_COMMITTED изоляции транзакции, два оператора SELECT гарантированновыполнить атомарно?Или я рискую изменить данные между отдельными инструкциями SELECT?Обсуждает ли спецификация SQL подобные вещи?

РАЗЪЯСНЕНИЕ : Когда я говорю «атомарный», я не имею в виду «А» в ACID.Я имею в виду, что я ожидаю, что таблицы отделов и сотрудников будут заблокированы для чтения до завершения запроса.

Ответы [ 3 ]

3 голосов
/ 08 апреля 2011

Да, оператор является атомарным, но да, данные могут меняться между двумя чтениями.

Read Committed только гарантирует, что вы не читаете грязные данные, он ничего не обещает о согласованности операций чтения, для которых вам потребуется более высокий уровень изоляции.

Как вы сказали, вы примете пример SQL Server ...

Соединение 1

(Предполагается, что уровень изоляции зафиксирован при пессимистическом чтении)

CREATE TABLE employee
(
name VARCHAR(50),
DepartmentID INT
)

CREATE TABLE department
(
DepartmentID INT
)

INSERT INTO department VALUES (1)
INSERT INTO employee VALUES ('bob',1)

declare @employee TABLE
(
name VARCHAR(50),
DepartmentID INT
)


WHILE ((SELECT COUNT(*) FROM @employee) < 2)
BEGIN
DELETE FROM  @employee

INSERT INTO @employee
SELECT employee.*
FROM   employee 
       LEFT JOIN department 
          ON employee.DepartmentID = department.DepartmentID
UNION
SELECT employee.*
FROM   employee
       RIGHT JOIN department
          ON employee.DepartmentID = department.DepartmentID

END;          

SELECT * FROM @employee

Соединение 2

while (1=1)
UPDATE employee SET name = CASE WHEN name = 'bob' THEN 'bill' else 'bob' END

Теперь вернитесь к соединению 1

name                                               DepartmentID
-------------------------------------------------- ------------
bill                                               1
bob                                                1

(Не забудьте переключиться обратно на Соединение 2, чтобы убить его!)

Специальная документация, охватывающая это READ COMMITED поведение здесь

Тип общей блокировки определяет, когда это будет выпущено. Рядные замки выпущен до следующего ряда обработанный. Блокировки страниц снимаются когда следующая страница прочитана, и таблица блокировки снимаются при утверждении отделка.

1 голос
/ 08 апреля 2011

РЕДАКТИРОВАТЬ: обратите внимание, что мой ответ неправильный, но я не хочу его удалять, потому что я думаю, что он ссылается на хорошие вопросы и имеет хорошие комментарии.

Каждая отдельная транзакция является атомарной.

A UNION с использованием нескольких подзапросов - это одна команда T-SQL, одна транзакция и она будет атомарной.

Это, отчасти, причина для того, чтобы избежать неэффективных запросов (или sprocs, если на то пошло), поскольку их атомарная природа может задерживать другие транзакции.

EDIT: Пожалуйста, смотрите этот вопрос для более интересной информации об атомарности подзапросов

Является ли обновление вложенной выбранной атомарной операцией?

РЕДАКТИРОВАТЬ: Очевидно, я не прав.

Это хорошая дискуссия по теме: Атомная UPSERT в SQL Server 2005 , где Ремус представляет хороший пример. Извини, что сомневаюсь в тебе, Мартин ....

1 голос
/ 08 апреля 2011

Использование UNION удалит все повторяющиеся записи, которые могут быть возвращены из любого объединенного запроса, поэтому не совсем атомарные.Используйте UNION ALL, если вам нужны все записи из всех объединенных запросов.UNION ALL может быть намного быстрее, чем UNION.

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