前几天我在 StackOverflow 上遇到了这个问答。引用问题作者的评论,情况似乎“有些可怕”。本次问答中也设置了类似的情况。
我的经验法则一直是 SQL 中的单个语句“原子地”执行。也就是说,在任何默认配置下,成功执行的单个语句(即没有死锁或中止)不存在任何潜在的并发问题。
然而我链接的两个问答表明并非如此。
说明问题的最基本场景似乎是这种自连接:
SELECT
t1.*
,t2.*
FROM
some_table AS t1
FULL OUTER JOIN
some_table AS t2
ON t2.id = t1.id
Run Code Online (Sandbox Code Playgroud)
是否存在不需要t1与 完全一致的情况t2,因此此查询可能会在全连接的一侧或另一侧返回 NULL,因为 t1 的数据与 t2 的数据是在不同的时间获取的因此每个可能引用不同的数据(即使它是在单个语句中引用的同一个表)?
我的假设始终是单个语句(引用多个表,或多次引用某些表)在某个时间步骤获取它所需的所有数据,作为数据库的单个一致快照。如果隔离级别为READ COMMITTED,那么我假设快照是单个语句开始时所有已提交数据的快照。
我对 RCSI 功能的理解是,它将这种假定的快照保证扩展到多语句事务。
我很震惊(虽然并不完全惊讶)发现事实似乎并非如此,而且我多年来的基本理解似乎被颠覆了。
有关这方面的信息似乎非常少。正如2014 年这篇文章的作者所说,这种行为似乎“甚至能够误导经验丰富的数据库从业者”。
该文章表明,即使是非常常见的 SELECT 查询样式似乎也能够在执行过程中修改其基础数据,并返回违反 WHERE 子句的显式逻辑标准的结果。这种行为方式可能成为默认行为,这似乎很荒谬。
问题
Microsoft(或 SQL 标准)是否有任何信息明确指定并确认此行为?
为了保证单个语句相当于所有数据的单个一致快照,需要进行哪些设置(在会话级别或语句级别)?