单行INSERT原子(对于外部读者)?想象一下,它发生在一个包含1M列的表上。
在执行单个true
语句(即“单行”类型)时,是否可能同时发生读取操作(可能使用“未提交的”读取“隔离级别”) 某些值(列)?
我对MS SQL Server的行为特别感兴趣,但我认为这对所有主要供应商来说都是类似的。
关于此事的官方文件链接的奖励积分。
答案 0 :(得分:2)
只阅读了一些值?
是的,这可能发生。 DML在某种意义上是原子的,写入是全部或全部持久化,但并发读取可以非常奇怪的方式观察部分写入。对于多行写入,这显然是可能的,但即使单行写入对读者来说也不是原子的。
例如,您可能会发现插入是针对一个非聚集索引完成的,而不是针对另一个非聚簇索引。对于罕见的人为案例的读者来说,这是可以理解的。例如,如果你说:
select *
from T t1 with (index(1))
full outer join T t2 with (index(2)) on (someUniqueCondition)
您可以有效地获得两个非零的索引之间的差异。索引提示不是实现此演示所必需的。
答案 1 :(得分:2)
如评论中所述,SQL Server不支持一百万列。但是,您应该能够只用两列来观察问题(在适当的情况下)。
使用READUNCOMMITTED
(或NOLOCK
)时,答案为“是”。在文档中查找引用非常困难,但here是一个讨论它的博客。
关键问题是跨越多个页面的行。只要您有LOB或varchar(max)
或类似类型的列,就会出现这种情况。如果另一个事务正在更新包含大对象值的页面,则并发READUNCOMMITTED
查询可以读取部分值。如果你有多个大型物体,情况也是如此。有些可能有新值,有些可能有旧值。因此,您可以在单个记录中获得不一致的结果。
对于存储在单个页面上的记录,我认为不会发生同样的事情(至少在实践中)。如果您有一个多语句事务在不同时间更新不同的字段,而不是单个语句,则可能会发生这种情况。
此外,隔离级别越高,就不会发生这种情况。实际上,READ_UNCOMMITTED
是一种绕过某些数据库完整性检查以提高性能的方法 - 这需要放松一些ACID属性。