问题标签 [read-committed-snapshot]
For questions regarding programming in ECMAScript (JavaScript/JS) and its various dialects/implementations (excluding ActionScript). Note JavaScript is NOT the same as Java! Please include all relevant tags on your question; e.g., [node.js], [jquery], [json], [reactjs], [angular], [ember.js], [vue.js], [typescript], [svelte], etc.
sql-server - tsql 等待更改,读取已提交快照打开
嗨 Stackoverflow 社区,
让我请求您的帮助,因为我确实遇到了一个关键问题。
我们有两个链接服务器,都是 Microsoft SQL Server:CRM 和 DW 服务器。CRM系统的一些变化会触发一个程序来立即获取DW服务器的更新,它的工作方式是CRM系统调用DW服务器来更新记录。在我的情况下,来自CRM 和 DW sql 服务器的CRM 系统的更新被称为同时,问题就从这里开始了。
DW 服务器仅在事务开始之前尝试读取更改并获取记录。是的,这是因为 CRM 服务器使用:
读取提交的快照
不幸的是,我们无法更改 CRM sql 服务器上的隔离级别。简单的解释——CRM 来自第三方提供商,他们想限制我们做出这些可能性。
有没有其他方法,等待事务提交,然后在提交后读取最新数据?
如果缺少信息,请告诉我,然后我将提供更多见解。
sql - 在 RCSI 下并行插入不存在的行
我尝试将一些行加载到目标表中,但前提是它们尚不存在。一个经典的左连接查询解决了这个问题:
此插入从不同用户并行运行多次,这些用户大部分时间都尝试插入相同的数据。
我看到来自不同用户的表中有很多重复项(SomeData 列上还没有唯一约束),这很奇怪,因为左连接应该检测到这一点并防止插入已经在表中的数据。
我调查并看到数据库处于 RCSI(读取提交的快照隔离)级别。我的想法是所有并行会话都认为他们是第一个插入数据的,并且都成功地做到了。
我怎么能在 RCSI 下插入呢?如果有一个会话已经在执行其左连接插入内容,我希望每个会话都等待。
任何帮助表示赞赏,谢谢!PS:不幸的是,我不允许更改数据库隔离级别。
sql-server - SQL Server - 启用读取已提交快照时处理事务的方式不一致
概述:
SQL 似乎在执行更新时从另一个会话中的不完整事务中读取“脏”信息,即使我们试图只读取已提交的数据。一些非常具体的标准必须是真实的,这个问题才会发生(很难重现 - 但我们可以在这里这样做)。
如何重现行为
SQL2017 或 SQL2019 或 Azure SQL
确定要测试的数据库并打开 Read Committed Snapshot。(设置 READ_COMMITTED_SNAPSHOT ON WITH NO_WAIT)
在数据库中运行 ScenarioPrep.SQL 脚本(如下)以创建测试对象。
- 这将创建 2 个表——一个“父”表和一个“子”表。
- 请注意,父表有两个条目,“地球”和“火星”
- 请注意,子表有 1 个条目,其父行的 id 名为“Earth”。火星没有孩子。
首先打开两个附加的 SSMS 会话,准备同时运行剩余的两个脚本(如下),其中 One.sql 在一个窗口中,Two.sql 在另一个窗口中。
- 请注意,One.sql 设置初始条件,然后在事务中包含两个更新语句。
- 请注意,Two.sql 尝试更新也在第一个脚本中更新的记录。
执行 One.sql 脚本。此脚本在事务中间有一个延迟,以帮助重现测试条件。
在 One.sql 运行时(特别是在延迟期间),在第二个窗口中执行 Two.sql。
请注意第二个窗口中的意外结果。地球记录意外更新。更新不应该成功,因为在任何时候都没有一个已提交的事务,其父“地球”记录的状态为 2,子记录的状态为 0。在事务之前,地球及其子记录都在状态为 0。交易后,地球和它的孩子都处于状态 2。
但是,Two.sql 确实成功更新了“地球”记录,因为它以某种方式将父级读取为状态为 2,而子级在延迟期间读取为状态为 0——但此时这不是一个提交的事务. 这是更新发生时不应该看到的“脏”状态。更新应该看到在另一个会话中提交事务之前或之后的状态。
预期的结果是 Two.sql 脚本不会更新任何记录,因为在任何时候都没有一个 COMMITTED 事务,其中 earth 处于状态 2 而它的孩子处于状态 0。事实上,在大多数情况下,这证明是真的。
观察
仅当以下所有条件都为真时,才会出现此问题:
- 数据库处于已提交读快照模式。
- 火星记录存在(即使它不受任何交易的影响)
- Mars 记录的状态为 2(部分匹配 Two.sql 中的 where 子句)
- Mars 记录在表中比 Earth 记录更早(具有较低的主键值)。
- 执行的操作是 UPDATE(用 select 替换更新会产生预期的结果)。
- 更新发生在跨两个或多个表的联接期间。
- Two.SQL 的事务模式是 Read Committed(具有讽刺意味的是,Read Uncommitted 正确阻塞,直到另一个事务完成并按预期工作)。
- 当然,在第一个事务中必须有足够的延迟才能发生测试场景。
如上所述,以下任何更改都会导致问题消失: 更改父表中 Mars 和 Earth Record 的顺序。从父表中删除 mars 记录(证明不相关的记录会影响另一个记录的更新方式。)将 Mars 记录置于 2 以外的状态。将 Update 更改为其他一些操作,例如 select。开启已提交读快照模式。
当然,从 One.sql 中的两个更新语句中删除事务会导致问题一直发生,但在这种情况下会发生这种情况。将两个更新语句包装在事务中的全部目的是避免这种情况。
回购代码
以下是重现该行为所需的三个代码文件:
场景准备.sql:
一.sql:
二.Sql: