简体   繁体   English

SQL Server 2014 In-Memory上一个事务中止异常

[英]SQL Server 2014 In-Memory previous transaction aborted exception

I'm working on a large scale project that is currently in production. 我正在开展一个目前正在生产的大型项目。 We have a big process that recently changed to use In-Memory Tables with SQL 2014 for performance efficiency. 我们有一个很大的流程,最近改为使用SQL 2014 In-Memory Tables来提高性能。

The Process uses: 该过程使用:

  • 51 In-Memory SQL Tables. 51内存中的SQL表。
  • 50 Stored Procedures that loads data(Insert) from about 150 regular SQL Tables. 50个存储过程,从大约150个常规SQL表加载数据(Insert)。
  • 300 Validations (short stored procedure) Selecting from those 50 In-Memory Tables (And insert to In-Memory table that save the validation errors if exists). 300个验证(短存储过程)从那些50个内存表中选择(并插入到内存表中,如果存在则保存验证错误)。

We are calling this Process from ADO.Net, loads stored procedure first and then validations, each SP use different SQL Connection . 我们从ADO.Net调用此进程,首先加载存储过程然后验证,每个SP使用不同的SQL Connection In normal use, everything works fine and takes about 1.5 second. 在正常使用中,一切正常,大约需要1.5秒。

Under stress test (6 Clients X 100 Tasks) for 30 minutes. 在压力测试(6个客户X 100任务)下30分钟。 After several minutes we are starting to get this SQL Exception (1 SQL Exception for every 20 tasks): 几分钟后,我们开始得到这个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 内存优化表中的事务

The Exception is not clear. 例外情况尚不清楚。 We are not using BEGIN TRANSACTION in the process. 我们在此过程中未使用BEGIN TRANSACTION The SQL Exception occurs in different stored procedures each time. 每次都会在不同的存储过程中发生SQL Exception

After days of investigation we are stuck and we have no ideas any more. 经过几天的调查,我们陷入困境,我们不再有任何想法。 Asking your help to undersand what can cause this exception and how to deal with it. 请求您帮助解决导致此异常的原因以及如何处理此异常。

There is not enough info to really track down the problem, but we can try to help you by trying to explain what that error means and how it could happen. 没有足够的信息来真正追查问题,但我们可以尝试解释该错误的含义以及可能发生的方式来帮助您。

First, as you probably know already, when Memory Optimized Table (MOT) participates in transaction, kind of optimistic concurrency control, avoid any locks and block waiting on that locks. 首先,正如您可能已经知道的那样,当内存优化表(MOT)参与事务时,一种乐观的并发控制,避免任何锁定和阻塞等待锁定。 Instead, when some kind of concurrency conflict is detected, one of the conflicting transactions is doomed and will be rolled back. 相反,当检测到某种并发冲突时,其中一个冲突的事务将注定失败并将被回滚。

Each row of MOT has several timestamps assigned which define if transaction can see this row or not. MOT的每一行都分配了几个时间戳,这些时间戳定义了事务是否可以看到该行。

For transactions that access MOT, special validation phase is performed before commit. 对于访问MOT的事务,在提交之前执行特殊验证阶段。 So whole transaction consists of three phases - regular, validation and commit. 因此,整个事务包括三个阶段 - 常规,验证和提交。

During regular phase, writes to the tables made by transaction are not visible to other transactions, except deletes and updates visible to other deletes and updates, and if one transaction writes the same row as the other, write-write conflict occurs and one transaction is doomed immediatly. 在常规阶段,对事务所做的表的写入对其他事务是不可见的,除了对其他删除和更新可见的删除和更新,并且如果一个事务与另一个事务写入相同的行,则发生写 - 写冲突并且一个事务是立即注定要失败。

Now most interesting for your problem is validation phase. 现在最有趣的问题是验证阶段。 Here, transaction validates things like was REPEATABLE READ or SERIALIZED isolation levels violated. 在这里,事务验证违反了REPEATABLE READ或SERIALIZED隔离级别的内容。 Suppose transaction runs under REPEATABLE READ, read some row at the beginning of transaction, and in validation phase it sees that the same row was updated by another transaction (remember that writes of other transactions are not visible unless you write to the same row, but here you just read). 假设事务在REPEATABLE READ下运行,在事务开始时读取一行,并且在验证阶段它看到同一行由另一个事务更新(请记住,除非您写入同一行,否则其他事务的写入不可见,但是在这里你只是阅读)。 Transaction is doomed here and will be rolled back. 交易在这里注定要失败并将被回滚。

Now, important thing is when validation phase begins, writes made by this transaction (let's name it transaction A, which is in validation phase) become visible to another transactions. 现在,重要的是当验证阶段开始时,此事务所做的写入(让我们将其命名为事务A,处于验证阶段)对另一个事务是可见的。 But note they are not commited yet. 但请注意,他们尚未提交。 If another transaction (B) reads such data (written by transaction which is now in validation phase but not yet commited), it gets the dependency on A. That means A should be commited and only after that B could be commited. 如果另一个事务(B)读取这样的数据(由现在处于验证阶段但尚未提交的事务编写),它将获得对A的依赖。这意味着A应该被提交,并且只有在提交了B之后才能提交。 If for some reason transaction A fails in validation phase, transaction B will be doomed too, with exception you have in your question. 如果由于某种原因,事务A在验证阶段失败,事务B也将注定失败,除了你的问题。

Now remember that even if you don't explicitly begin transactions, each statement is executed inside transaction anyway. 现在请记住,即使您没有明确地开始事务,也会在事务内部执行每个语句。 You might think that simple statements cannot cause such problems, but there are statements like MERGE that internally might execute several read and write operations, and they will be performed inside transaction. 您可能认为简单的语句不会导致这样的问题,但是像MERGE这样的语句在内部可能会执行多个读写操作,并且它们将在事务内部执行。

An example how your error might occur (this is just to give you some ideas): 您的错误可能发生的一个示例(这只是为了给您一些想法):

  1. statement A performs MERGE statement on some table 语句A在某些表上执行MERGE语句
  2. It enters validation phase. 它进入验证阶段。
  3. statement B performs MERGE and reads some data written by A. 语句B执行MERGE并读取由A写的一些数据。
  4. We run under SERIALIZABLE isolation level, and A in validation phase notices that phantom row was inserted by some other statement C. SERIALIZABLE level is violated and A will be rolled back. 我们在SERIALIZABLE隔离级别下运行,并且在验证阶段A注意到其他语句C插入了幻像行。违反了SERIALIZABLE级别并且将回滚A。
  5. B has dependency on A and will be rolled back too with your exception. B依赖于A,并且在您的例外情况下也会回滚。

Hope this information will help you to find the root of your problem. 希望这些信息能帮助您找到问题的根源。

What you can do also to track the issue is set isolation level to SNAPSHOT. 您还可以通过将隔离级别设置为SNAPSHOT来跟踪问题。 Then validation step is not performed as I understand and this error should not appear any more. 然后根据我的理解不执行验证步骤,此错误不应再出现。

Since In-Memory tables create COMMIT DEPENDENCIES, you may be facing that kind of situation. 由于In-Memory表创建COMMIT DEPENDENCIES,您可能会遇到这种情况。

In other words, after some time and under a stress test, is normal your database be more busy and creating some bottlenecks during the VALIDATION PHASE and COMMIT PHASE. 换句话说,经过一段时间并且在压力测试之后,正常情况下您的数据库会更加繁忙并在验证阶段和COMMIT阶段中产生一些瓶颈。 So, you may accessing records that ARE NOT COMMITED YET by previous procedures: error 41301 ("a previous transaction that current transaction tool a dependency has aborted...") 因此,您可以通过以前的过程访问不常见的记录:错误41301(“当前事务工具依赖项已中止的先前事务...”)

You may force the COMMIT of data between transactions and, mainly, before start a new procedure that will utilize data from that transaction. 您可以在事务之间强制执行COMMIT,主要是在启动将使用该事务数据的新过程之前。 In some scenarios, a simples "Select Count(*)" may force that commit. 在某些情况下,简单的“选择计数(*)”可能会强制提交。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM