我发出一个SQL查询,包含使用UNION分组的多个SELECT:
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中的“A”。我的意思是我希望在查询完成之前对department和employee表进行读锁定。
答案 0 :(得分:3)
是的,该声明是原子的,但是数据可以在2次读取之间发生变化。
Read Committed
只能保证你不会读取脏数据,因为你需要更高的隔离级别,所以不会对读取的一致性做出任何承诺。
正如您所说,您将接受SQL Server示例...
(假设在悲观的读取提交隔离级别下)
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
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
行为is here
共享锁定类型决定何时 它将被释放。行锁是 在下一行之前发布了 处理。页锁已发布 当读取下一页时,和表 在声明时释放锁 饰面。
答案 1 :(得分:1)
使用UNION
将删除可能从任何联合查询返回的任何重复记录,因此不完全是原子的。如果您想要所有联合查询的所有记录,请使用UNION ALL
。 UNION ALL
也可以UNION
快得多。
答案 2 :(得分:1)
编辑:请注意,我的回答是不正确的,但我不想删除它,因为我认为它链接到好问题并且有很好的评论。
每笔交易都是原子的。
使用多个子查询的UNION
是单个T-SQL命令,单个事务,并且是原子的。
这部分地是避免低效查询(或者sprocs)的原因,因为它们的原子性质可以延迟其他事务。
编辑: 有关子查询原子性的更多有趣信息,请参阅此问题
Is update with nested select atomic operation?
编辑:显然我错了。
这是关于这个主题的一个很好的讨论:Atomic UPSERT in SQL Server 2005 Remus就是一个很好的例子。很抱歉怀疑你,马丁......