SQL Server 2014 In-Memory previous transaction aborted异常
SQL Server 2014 In-Memory previous transaction aborted exception
我正在处理一个目前正在制作中的大型项目。
我们有一个大流程,最近更改为使用 In-Memory Tables
和 SQL 2014 以提高性能效率。
流程使用:
- 51 个内存中 SQL 个表。
- 50 个从大约 150 个常规 SQL 表加载数据(插入)的存储过程。
- 300 次验证(短存储过程)从这 50 个内存表中选择(并插入到内存中 table 以保存验证错误(如果存在)。
我们从 ADO.Net 调用这个进程,首先加载存储过程然后验证,每个 SP 使用不同的 SQL Connection
。
在正常使用中,一切正常,大约需要 1.5 秒。
压力测试(6 个客户端 X 100 个任务)30 分钟。
几分钟后,我们开始得到这个 SQL Exception
(每 20 个任务有 1 个 SQL 异常):
A previous transaction that the current transaction took a dependency on has aborted,
and the current transaction can no longer commit.
Transactions in Memory-Optimized Tables
异常不明确。
我们在此过程中没有使用 BEGIN TRANSACTION
。 SQL Exception
每次都出现在不同的存储过程中。
经过几天的调查,我们陷入困境,我们再也没有想法了。
请您帮助了解导致此异常的原因以及处理方法。
没有足够的信息来真正追踪问题,但我们可以尝试通过解释该错误的含义以及它是如何发生的来帮助您。
首先,正如您可能已经知道的那样,当内存优化 Table (MOT) 参与事务时,一种乐观的并发控制,避免任何锁并阻止等待该锁。相反,当检测到某种并发冲突时,其中一个冲突事务注定会被回滚。
MOT 的每一行都分配了几个时间戳,用于定义事务是否可以看到这一行。
对于访问 MOT 的事务,在提交之前执行特殊的验证阶段。所以整个交易由三个阶段组成——常规、验证和提交。
在常规阶段,事务对 table 的写入对其他事务不可见,除了删除和更新对其他删除和更新可见,并且如果一个事务写入与另一个相同的行, 发生写-写冲突, 一笔交易直接挂掉
现在您的问题最有趣的是验证阶段。在这里,事务验证诸如是否违反了可重复读取或序列化隔离级别之类的事情。假设 REPEATABLE READ 下的事务 运行s,在事务开始时读取了一些行,并且在验证阶段它看到同一行被另一个事务更新了(记住,其他事务的写入是不可见的,除非你写入同一行,但在这里你只是阅读)。事务在这里注定,将被回滚
现在,重要的是当验证阶段开始时,此事务(我们将其命名为事务 A,处于验证阶段)所做的写入对另一个事务可见。但请注意,它们尚未提交。如果另一个事务 (B) 读取此类数据(由现在处于验证阶段但尚未提交的事务写入),它会获得对 A 的依赖。这意味着 A 应该被提交,并且只有在 B 之后才能提交。如果由于某种原因交易 A 在验证阶段失败,交易 B 也将失败,但您的问题除外。
现在请记住,即使您没有显式开始事务,每条语句都会在事务内执行。你可能认为简单的语句不会引起这样的问题,但是像MERGE这样的语句,内部可能会执行多个读写操作,它们会在事务内部执行。
您的错误可能发生的示例(这只是给您一些想法):
- 语句 A 在某些 table
上执行 MERGE 语句
- 进入验证阶段。
- 语句 B 执行 MERGE 并读取 A 写入的一些数据。
- 我们 运行 在 SERIALIZABLE 隔离级别下,A 在验证阶段注意到幻像行被其他语句 C 插入。SERIALIZABLE 级别被违反,A 将被回滚。
- B 对 A 具有依赖性,并且也会因您的异常而回滚。
希望这些信息能帮助您找到问题的根源。
您还可以通过将隔离级别设置为 SNAPSHOT 来跟踪问题。然后按照我的理解没有执行验证步骤,这个错误应该不会再出现了。
由于 In-Memory 表创建了 COMMIT DEPENDENCIES,您可能会遇到这种情况。
换句话说,经过一段时间并在压力测试下,您的数据库会更加繁忙并在验证阶段和提交阶段产生一些瓶颈是正常的。因此,您可能会访问之前过程尚未提交的记录:错误 41301 ("a previous transaction that current transaction tool a dependency has aborted...")
您可以在事务之间强制提交数据,主要是在启动将利用该事务中的数据的新过程之前。在某些情况下,简单 "Select Count(*)" 可能会强制执行该提交。
我正在处理一个目前正在制作中的大型项目。
我们有一个大流程,最近更改为使用 In-Memory Tables
和 SQL 2014 以提高性能效率。
流程使用:
- 51 个内存中 SQL 个表。
- 50 个从大约 150 个常规 SQL 表加载数据(插入)的存储过程。
- 300 次验证(短存储过程)从这 50 个内存表中选择(并插入到内存中 table 以保存验证错误(如果存在)。
我们从 ADO.Net 调用这个进程,首先加载存储过程然后验证,每个 SP 使用不同的 SQL Connection
。
在正常使用中,一切正常,大约需要 1.5 秒。
压力测试(6 个客户端 X 100 个任务)30 分钟。
几分钟后,我们开始得到这个 SQL Exception
(每 20 个任务有 1 个 SQL 异常):
A previous transaction that the current transaction took a dependency on has aborted,
and the current transaction can no longer commit.
Transactions in Memory-Optimized Tables
异常不明确。
我们在此过程中没有使用 BEGIN TRANSACTION
。 SQL Exception
每次都出现在不同的存储过程中。
经过几天的调查,我们陷入困境,我们再也没有想法了。 请您帮助了解导致此异常的原因以及处理方法。
没有足够的信息来真正追踪问题,但我们可以尝试通过解释该错误的含义以及它是如何发生的来帮助您。
首先,正如您可能已经知道的那样,当内存优化 Table (MOT) 参与事务时,一种乐观的并发控制,避免任何锁并阻止等待该锁。相反,当检测到某种并发冲突时,其中一个冲突事务注定会被回滚。
MOT 的每一行都分配了几个时间戳,用于定义事务是否可以看到这一行。
对于访问 MOT 的事务,在提交之前执行特殊的验证阶段。所以整个交易由三个阶段组成——常规、验证和提交。
在常规阶段,事务对 table 的写入对其他事务不可见,除了删除和更新对其他删除和更新可见,并且如果一个事务写入与另一个相同的行, 发生写-写冲突, 一笔交易直接挂掉
现在您的问题最有趣的是验证阶段。在这里,事务验证诸如是否违反了可重复读取或序列化隔离级别之类的事情。假设 REPEATABLE READ 下的事务 运行s,在事务开始时读取了一些行,并且在验证阶段它看到同一行被另一个事务更新了(记住,其他事务的写入是不可见的,除非你写入同一行,但在这里你只是阅读)。事务在这里注定,将被回滚
现在,重要的是当验证阶段开始时,此事务(我们将其命名为事务 A,处于验证阶段)所做的写入对另一个事务可见。但请注意,它们尚未提交。如果另一个事务 (B) 读取此类数据(由现在处于验证阶段但尚未提交的事务写入),它会获得对 A 的依赖。这意味着 A 应该被提交,并且只有在 B 之后才能提交。如果由于某种原因交易 A 在验证阶段失败,交易 B 也将失败,但您的问题除外。
现在请记住,即使您没有显式开始事务,每条语句都会在事务内执行。你可能认为简单的语句不会引起这样的问题,但是像MERGE这样的语句,内部可能会执行多个读写操作,它们会在事务内部执行。
您的错误可能发生的示例(这只是给您一些想法):
- 语句 A 在某些 table 上执行 MERGE 语句
- 进入验证阶段。
- 语句 B 执行 MERGE 并读取 A 写入的一些数据。
- 我们 运行 在 SERIALIZABLE 隔离级别下,A 在验证阶段注意到幻像行被其他语句 C 插入。SERIALIZABLE 级别被违反,A 将被回滚。
- B 对 A 具有依赖性,并且也会因您的异常而回滚。
希望这些信息能帮助您找到问题的根源。
您还可以通过将隔离级别设置为 SNAPSHOT 来跟踪问题。然后按照我的理解没有执行验证步骤,这个错误应该不会再出现了。
由于 In-Memory 表创建了 COMMIT DEPENDENCIES,您可能会遇到这种情况。
换句话说,经过一段时间并在压力测试下,您的数据库会更加繁忙并在验证阶段和提交阶段产生一些瓶颈是正常的。因此,您可能会访问之前过程尚未提交的记录:错误 41301 ("a previous transaction that current transaction tool a dependency has aborted...")
您可以在事务之间强制提交数据,主要是在启动将利用该事务中的数据的新过程之前。在某些情况下,简单 "Select Count(*)" 可能会强制执行该提交。