最近、高いTRANSACTION_MUTEX
に遭遇しました クライアントシステムでの累積待機時間。この待機タイプが「高待機」リストの一番上にあると思ったケースを思い出せませんでした。このタイプの全体的な待機時間をどのような要因で押し上げることができるのか知りたいと思いました。
BooksOnlineのTRANSACTION_MUTEX
の定義 これは、「複数のバッチによるトランザクションへのアクセスの同期中に発生する」ということです。 SQL Serverエンジン内の多くの領域でこのタイプの機能が公開されていないため、調査は次のテクノロジに絞り込まれました。
- 非推奨の
sp_getbindtoken
およびsp_bindsession
バインドされた接続を処理するために使用されるシステムストアドプロシージャ - 分散トランザクション
- MARS(複数のアクティブな結果セット)
私の目標は、各テクノロジーをテストし、それがTRANSACTION_MUTEX
に影響を与えたかどうかを確認することでした。 待機タイプ。
私が実行した最初のテストでは、非推奨のsp_getbindtoken
を使用しました およびsp_bindsession
ストアドプロシージャ。 sp_getbindtoken
sp_bindsession
で使用できるトランザクション識別子を返します 同じトランザクションで複数のセッションをバインドします。
各テストシナリオの前に、テストSQLServerインスタンスの待機統計を必ずクリアしました。
DBCC SQLPERF('waitstats', CLEAR); GO
私のテストSQLServerインスタンスは、SQL Server 2012 SP1 Developer Edition(11.0.3000)を実行していました。私はCreditサンプルデータベースを使用しましたが、スキーマとデータの配布はこの記事の主題に直接関連しておらず、運転するために必要ではなかったため、必要に応じてAdventureWorksなどの他の種類のサンプルデータベースを使用できます。 TRANSACTION_MUTEX
待ち時間。
sp_getbindtoken / sp_bindsession
SQL Server Management Studioの最初のセッションウィンドウで、次のコードを実行してトランザクションを開始し、他の計画されたセッションによる参加用のバインドトークンを出力しました。
USE Credit; GO BEGIN TRANSACTION; DECLARE @out_token varchar(255); EXECUTE sp_getbindtoken @out_token OUTPUT; SELECT @out_token AS out_token; GO
これにより、@out_token
が返されました S/Z5_GOHLaGY<^i]S9LXZ-5---.fE---
の 。 2つの別々のSQLServerManagement Studioクエリウィンドウで、次のコードを実行して既存のセッションに参加しました(共有トランザクションにアクセスします)。
USE Credit; GO EXEC sp_bindsession 'S/Z5_GOHLaGY<^i]S9LXZ-5---.fE---';
そして、最初のセッションウィンドウを開いたまま、次のループを開始して、現在の日時に等しい請求日で請求テーブルのテーブルを更新し、他の2つのウィンドウで同じロジックを実行しました(ループ):
WHILE 1 = 1 BEGIN UPDATE dbo.charge SET charge_dt = SYSDATETIME(); END
数秒後、実行中の各クエリをキャンセルしました。 3つのセッションのうち、実際に更新を実行できたのは1つだけでしたが、他の2つのセッションは同じトランザクションにアクティブに参加していました。そして、TRANSACTION_MUTEX
を見た場合 待機タイプ、実際に増加したことがわかります:
SELECT [wait_type], [waiting_tasks_count], [wait_time_ms], [max_wait_time_ms], [signal_wait_time_ms] FROM sys.dm_os_wait_stats WHERE wait_type = 'TRANSACTION_MUTEX';
この特定のテストの結果は次のとおりです。
wait_type waiting_tasks_count wait_time_ms max_wait_time_ms signal_wait_time_ms TRANSACTION_MUTEX 2 181732 93899 0
したがって、2つの待機中のタスク(ループを介して同じテーブルを同時に更新しようとした2つのセッション)があったことがわかります。 SET NOCOUNT ON
を実行していなかったので 、最初に実行されたUPDATE
のみを確認できました ループに変更が加えられました。いくつかの異なるバリエーション(たとえば、全体で4つのセッション、待機中の3つ)とTRANSACTION_MUTEX
を使用して、この同様の手法を試しました。 インクリメントは同様の動作を示しました。 TRANSACTION_MUTEX
も見ました セッションごとに異なるテーブルを同時に更新する場合の累積–したがって、TRANSACTION_MUTEX
を再現するために、ループ内の同じオブジェクトに対する変更は必要ありませんでした。 待ち時間の蓄積。
分散トランザクション
次のテストでは、TRANSACTION_MUTEX
かどうかを確認しました。 分散トランザクションの待機時間が増加しました。このテストでは、2つのSQL Serverインスタンスと、2つのインスタンスの間に接続されたリンクサーバーを使用しました。 MS DTCが実行され、適切に構成されていたため、ローカルのDELETE
を実行する次のコードを実行しました。 およびリモートのDELETE
リンクサーバーを介して変更をロールバックします:
USE Credit; GO SET XACT_ABORT ON; -- Assumes MS DTC service is available, running, properly configured BEGIN DISTRIBUTED TRANSACTION; DELETE [dbo].[charge] WHERE charge_no = 1; DELETE [JOSEPHSACK-PC\AUGUSTUS].[Credit].[dbo].[charge] WHERE charge_no = 1; ROLLBACK TRANSACTION;
TRANSACTION_MUTEX
ローカルサーバーでアクティビティが表示されませんでした:
wait_type waiting_tasks_count wait_time_ms max_wait_time_ms signal_wait_time_ms TRANSACTION_MUTEX 0 0 0 0
ただし、待機中のタスクの数はリモートサーバーで増加しました:
wait_type waiting_tasks_count wait_time_ms max_wait_time_ms signal_wait_time_ms TRANSACTION_MUTEX 1 0 0 0
したがって、同じトランザクションに何らかの形で複数のセッションが関与する1つの分散トランザクションがあることを考えると、これを確認するという私の期待が確認されました。
MARS(複数のアクティブな結果セット)
複数のアクティブな結果セット(MARS)の使用についてはどうですか? TRANSACTION_MUTEX
も表示されると思いますか MARSの使用に関連して蓄積しますか?
このために、SQL Server2012インスタンスとCreditデータベースに対してMicrosoftVisual Studioからテストされた次のC#コンソールアプリケーションコードを使用しました。私が実際に行っていることのロジックはあまり役に立ちません(各テーブルから1行を返します)が、データリーダーは同じ接続と接続属性MultipleActiveResultSets
上にあります はtrueに設定されているため、実際にMARSがTRANSACTION_MUTEX
を駆動できるかどうかを確認するだけで十分でした。 蓄積も:
string ConnString = @"Server=.;Database=Credit;Trusted_Connection=True;MultipleActiveResultSets=true;"; SqlConnection MARSCon = new SqlConnection(ConnString); MARSCon.Open(); SqlCommand MARSCmd1 = new SqlCommand("SELECT payment_no FROM dbo.payment;", MARSCon); SqlCommand MARSCmd2 = new SqlCommand("SELECT charge_no FROM dbo.charge;", MARSCon); SqlDataReader MARSReader1 = MARSCmd1.ExecuteReader(); SqlDataReader MARSReader2 = MARSCmd2.ExecuteReader(); MARSReader1.Read(); MARSReader2.Read(); Console.WriteLine("\t{0}", MARSReader1[0]); Console.WriteLine("\t{0}", MARSReader2[0]);
このコードを実行した後、TRANSACTION_MUTEX
の次の累積が表示されました :
wait_type waiting_tasks_count wait_time_ms max_wait_time_ms signal_wait_time_ms TRANSACTION_MUTEX 8 2 0 0
ご覧のとおり、MARSアクティビティ(ただし、簡単に実装されたもの)により、TRANSACTION_MUTEX
が上昇しました。 待機タイプの蓄積。また、接続文字列属性自体はこれを駆動しませんが、実際の実装は駆動します。たとえば、2番目のリーダーの実装を削除し、MultipleActiveResultSets=true
を使用して単一のリーダーを維持しました。 、そして予想通り、TRANSACTION_MUTEX
はありませんでした 待ち時間の蓄積。
結論
高いTRANSACTION_MUTEX
が表示されている場合 ご使用の環境で待機している場合は、この投稿で、これらの待機がどこから来ているのか、および待機が必要かどうかを判断するための3つの方法についての洞察が得られることを願っています。