【问题标题】:SQL Server 2014 In-Memory previous transaction aborted exceptionSQL Server 2014 In-Memory 以前的事务中止异常
【发布时间】:2015-09-21 12:17:56
【问题描述】:

我正在从事一个目前正在生产中的大型项目。 我们有一个大流程,最近更改为使用In-Memory Tables 和 SQL 2014 以提高性能。

流程使用:

  • 51 个内存中 SQL 表。
  • 50 个存储过程,从大约 150 个常规 SQL 表中加载数据(插入)。
  • 300 次验证(短存储过程)从这 50 个内存表中进行选择(如果存在,则插入到保存验证错误的内存表)。

我们从 ADO.Net 调用这个 Process,首先加载存储过程然后验证,每个 SP 使用不同的SQL Connection。 在正常使用中,一切正常,大约需要 1.5 秒。

进行 30 分钟的压力测试(6 个客户端 X 100 个任务)。 几分钟后,我们开始收到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 TRANSACTIONSQL Exception 每次出现在不同的存储过程中。

经过几天的调查,我们陷入了困境,我们不再有任何想法。 寻求您的帮助以了解可能导致此异常的原因以及如何处理它。

【问题讨论】:

  • 我看过这篇文章,但我不确定这是解决此问题的最佳方法。发生此异常是由于某种原因,我想了解原因。
  • 除此之外没有其他错误?您是否在程序中执行更新或删除?
  • @Evk 有时也会出现超时...我执行更新,但对于此检查,我已标记所有更新并且异常仍然发生。
  • The Exception is not clear 是的,因为您遗漏了大部分信息。发布异常 ToString,包括调用堆栈和它发生的代码。您似乎正在使用 System.Transactions 。详细说明它的用法。

标签: .net sql-server stored-procedures sql-server-2014 in-memory


【解决方案1】:

没有足够的信息来真正追查问题,但我们可以通过解释该错误的含义以及它是如何发生的来帮助您。

首先,您可能已经知道,当内存优化表 (MOT) 参与事务时,一种乐观并发控制,避免任何锁并阻塞等待该锁。相反,当检测到某种并发冲突时,其中一个发生冲突的事务注定要失败并回滚。

MOT 的每一行都分配了几个时间戳,这些时间戳定义了事务是否可以看到这一行。

对于访问 MOT 的事务,在提交之前会执行特殊的验证阶段。所以整个事务由三个阶段组成——常规、验证和提交。

在常规阶段,事务对表的写入对其他事务不可见,除了对其他删除和更新可见的删除和更新,如果一个事务与另一个事务写入同一行,则会发生写-写冲突,并且一笔交易立即注定失败。

现在对您的问题最感兴趣的是验证阶段。在这里,事务验证诸如是否违反了可重复读取或序列化隔离级别之类的事情。假设事务在 REPEATABLE READ 下运行,在事务开始时读取了一些行,并且在验证阶段它看到同一行已被另一个事务更新(请记住,除非您写入同一行,否则其他事务的写入是不可见的,但是在这里你刚刚读到)。交易在这里注定失败,将被回滚。

现在,重要的是当验证阶段开始时,此事务(我们将其命名为事务 A,它处于验证阶段)进行的写入对其他事务可见。但请注意,它们尚未提交。如果另一个事务 (B) 读取此类数据(由现在处于验证阶段但尚未提交的事务写入),它将获得对 A 的依赖。这意味着应该提交 A,并且只有在提交 B 之后才能提交。如果由于某种原因交易 A 在验证阶段失败,交易 B 也将注定失败,除非您的问题有例外。

现在请记住,即使您没有显式地开始事务,每个语句无论如何都会在事务内部执行。你可能认为简单的语句不会导致这样的问题,但是像 MERGE 这样的语句在内部可能会执行几个读写操作,它们会在事务内部执行。

一个你的错误可能发生的例子(这只是给你一些想法):

  1. 语句 A 对某个表执行 MERGE 语句
  2. 进入验证阶段。
  3. 语句 B 执行 MERGE 并读取 A 写入的一些数据。
  4. 我们在 SERIALIZABLE 隔离级别下运行,并且 A 在验证阶段注意到幻像行已被其他语句 C 插入。违反了 SERIALIZABLE 级别,A 将被回滚。
  5. B 依赖于 A,并且会因为您的异常而回滚。

希望这些信息能帮助您找到问题的根源。

您还可以通过将隔离级别设置为 SNAPSHOT 来跟踪问题。然后验证步骤没有按照我的理解执行,这个错误应该不会再出现了。

【讨论】:

  • 感谢您的详细回答。我们的数据库设置为 SNAPSHOT...您能否提供一些代码/示例来检索此异常?
  • 我目前无权访问 sql server 实例。然而,上面的解释应该足以重现几个相对简单的事务的异常
【解决方案2】:

由于 In-Memory 表创建 COMMIT DEPENDENCIES,您可能会面临这种情况。

换句话说,经过一段时间并在压力测试下,您的数据库会更加繁忙并在验证阶段和提交阶段产生一些瓶颈是正常的。因此,您可以访问之前的过程尚未提交的记录:错误 41301(“当前事务工具依赖项已中止的先前事务......”)

您可以强制在事务之间提交数据,主要是在开始使用来自该事务的数据的新程序之前。在某些情况下,简单的“Select Count(*)”可能会强制提交。

【讨论】:

  • 你能解释一下如何提交交易吗?什么意思 Select Count(*),应该写在哪里?
  • @MishaZaslavsky,您可以在更新记录后强制 COMMIT(数据在磁盘/数据库上进行物理更新)尝试选择。是的,它会导致一些延迟,但会强制 SQL 写入数据(提交)。您应该将其写在整个处理过程中涉及的一个(或多个)程序的末尾。请参阅:您在程序之间遇到问题,并且其中一个(或其中一些)在下一个开始之前也没有提交数据。
猜你喜欢
  • 1970-01-01
  • 2018-03-02
  • 1970-01-01
  • 1970-01-01
  • 2020-05-20
  • 2011-05-01
  • 2015-11-04
  • 2017-01-03
  • 2011-04-27
相关资源
最近更新 更多