【发布时间】:2022-08-04 00:05:46
【问题描述】:
我们正在尝试在事务范围内运行并行查询以提高代码的性能。我们要在数据库中进行一些相互没有连接的更改。我们可以像这样运行代码:
using(var tran = new System.Transactions.TransactionScope())
{
await queryMethod1Async();
await queryMethod2Async();
await queryMethod3Async();
tran.Complete();
}
然而,由于这些方法是相互独立的,我们希望像这样运行代码:
using(var tran = new System.Transactions.TransactionScope())
{
var tasks = new List<Task>();
tasks.Add(queryMethod1Async());
tasks.Add(queryMethod2Async());
tasks.Add(queryMethod3Async());
await Task.WhenAll(tasks);
tran.Complete();
}
我们在并行执行中遇到了一些问题:
- 并行运行查询似乎会升级事务。在升级过程中,有时会出现错误:
The wait operation timed out --> There is already an open DataReader associated with this Command which must be closed first.
at System.Data.SqlClient.SqlInternalConnectionTds.ExecuteTransactionYukon(TransactionRequest transactionRequest, String transactionName, IsolationLevel iso, SqlInternalTransaction internalTransaction, Boolean isDelegateControlRequest)
at System.Data.SqlClient.SqlDelegatedTransaction.Promote() --> Failure while attempting to promote transaction.
at System.Data.SqlClient.SqlDelegatedTransaction.Promote()
at System.Transactions.TransactionStatePSPEOperation.PSPEPromote(InternalTransaction tx)
at System.Transactions.TransactionStateDelegatedBase.EnterState(InternalTransaction tx) --> The transaction has aborted.
at System.Transactions.TransactionStateAborted.CheckForFinishedTransaction(InternalTransaction tx)
at System.Transactions.Transaction.Promote()
at System.Transactions.TransactionInterop.ConvertToOletxTransaction(Transaction transaction)
at System.Transactions.TransactionInterop.GetExportCookie(Transaction transaction, Byte[] whereabouts)
at System.Data.SqlClient.SqlInternalConnection.GetTransactionCookie(Transaction transaction, Byte[] whereAbouts)
at System.Data.SqlClient.SqlInternalConnection.EnlistNonNull(Transaction tx)
at System.Data.SqlClient.SqlInternalConnection.Enlist(Transaction tx)
at System.Data.ProviderBase.DbConnectionInternal.ActivateConnection(Transaction transaction)
经过一番调查,这似乎是因为在升级期间,使用了事务的原始连接,但在并行执行期间,该连接可能正在使用中。 我尝试启用MARS 以避免此问题,但这会导致不同的错误:
Current Microsoft Distributed Transaction Coordinator (MS DTC) transaction must be committed by remote client.
at System.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction)
at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, Boolean callerHasConnectionLock, Boolean asyncClose)
at System.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj, Boolean& dataReady)
at System.Data.SqlClient.TdsParser.Run(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj)
at System.Data.SqlClient.TdsParser.TdsExecuteTransactionManagerRequest(Byte[] buffer, TransactionManagerRequestType request, String transactionName, TransactionManagerIsolationLevel isoLevel, Int32 timeout, SqlInternalTransaction transaction, TdsParserStateObject stateObj, Boolean isDelegateControlRequest)
at System.Data.SqlClient.SqlInternalConnectionTds.ExecuteTransactionYukon(TransactionRequest transactionRequest, String transactionName, IsolationLevel iso, SqlInternalTransaction internalTransaction, Boolean isDelegateControlRequest)
at System.Data.SqlClient.SqlDelegatedTransaction.SinglePhaseCommit(SinglePhaseEnlistment enlistment) --> The transaction has aborted.
澄清一下,上述每个方法都创建了一个新的sqlconnection,并且我们已经正确配置了MSDTC
我不确定为什么会发生第二个错误,但我有一种感觉,我正在以错误的方式解决这个问题。是否可以在事务范围内执行并行查询,如果可以,正确的方法是什么?
-
恕我直言,正确的措辞应该是\“同时查询执行\",因为 TransactionScope()-context-manager 的作用域最终注入了一个 \"macro\"-structure 屏障,让所有 async-\"just\"-[CONCURRENT] 任务坐下来等待最慢,在代码执行只能稍后离开范围之前。这种手动同步屏障主要是异步的,“只是”-[CONCURRENT] 独立操作,否则不协调的任务不是上下文的属性+不是 True-[ PARALLEL] 问题,只是一个 \"exit-ALAP barrier\" 强制等待直到所有 \"just\"-[CONCURRENT] 流程完成
标签: c# sql-server parallel-processing transactions