Saya baru-baru ini menemukan TRANSACTION_MUTEX
tinggi akumulasi waktu tunggu pada sistem klien. Saya tidak dapat mengingat kasus di mana saya melihat jenis menunggu ini berada di dekat bagian atas daftar "menunggu tinggi" dan saya ingin tahu tentang faktor apa yang dapat mendorong jenis waktu tunggu keseluruhan ini.
Definisi Buku Online dari TRANSACTION_MUTEX
adalah bahwa itu "terjadi selama sinkronisasi akses ke transaksi oleh beberapa batch." Tidak banyak area di dalam mesin SQL Server yang mengekspos fungsionalitas jenis ini, jadi penyelidikan saya dipersempit ke teknologi berikut:
sp_getbindtoken
yang tidak digunakan lagi dansp_bindsession
prosedur tersimpan sistem yang digunakan untuk menangani koneksi terikat- Transaksi terdistribusi
- MARS (Beberapa Set Hasil Aktif)
Tujuan saya adalah menguji setiap teknologi dan melihat apakah itu memengaruhi TRANSACTION_MUTEX
jenis tunggu.
Tes pertama yang saya lakukan menggunakan sp_getbindtoken
yang sudah tidak digunakan lagi dan sp_bindsession
prosedur tersimpan. sp_getbindtoken
mengembalikan pengidentifikasi transaksi yang kemudian dapat digunakan oleh sp_bindsession
untuk mengikat beberapa sesi bersama pada transaksi yang sama.
Sebelum setiap skenario pengujian, saya memastikan untuk menghapus statistik tunggu instance SQL Server pengujian saya:
DBCC SQLPERF('waitstats', CLEAR); GO
Contoh pengujian SQL Server saya menjalankan SQL Server 2012 SP1 Developer Edition (11.0.3000). Saya menggunakan basis data sampel Kredit, meskipun Anda dapat menggunakan jenis basis data sampel lain seperti AdventureWorks jika Anda mau, karena skema dan distribusi data tidak secara langsung relevan dengan subjek artikel ini dan tidak diperlukan untuk mengemudi TRANSACTION_MUTEX
waktu tunggu.
sp_getbindtoken / sp_bindsession
Di jendela sesi pertama SQL Server Management Studio, saya mengeksekusi kode berikut untuk memulai transaksi dan mengeluarkan token ikat untuk pendaftaran oleh sesi lain yang direncanakan:
USE Credit; GO BEGIN TRANSACTION; DECLARE @out_token varchar(255); EXECUTE sp_getbindtoken @out_token OUTPUT; SELECT @out_token AS out_token; GO
Ini mengembalikan @out_token
dari S/Z5_GOHLaGY<^i]S9LXZ-5---.fE---
. Di dua jendela kueri SQL Server Management Studio terpisah, saya mengeksekusi kode berikut untuk bergabung ke sesi yang ada (mengakses transaksi bersama):
USE Credit; GO EXEC sp_bindsession 'S/Z5_GOHLaGY<^i]S9LXZ-5---.fE---';
Dan dengan jendela sesi pertama masih terbuka, saya memulai loop berikut untuk memperbarui tabel tabel biaya dengan tanggal pengisian yang sama dengan tanggal dan waktu saat ini, dan kemudian menjalankan logika yang sama di dua jendela lainnya (tiga sesi aktif di lingkaran):
WHILE 1 = 1 BEGIN UPDATE dbo.charge SET charge_dt = SYSDATETIME(); END
Setelah beberapa detik, saya membatalkan setiap kueri yang dieksekusi. Dari tiga sesi, hanya satu yang benar-benar dapat melakukan pembaruan – meskipun dua sesi lainnya secara aktif bergabung ke transaksi yang sama. Dan jika saya melihat TRANSACTION_MUTEX
tipe tunggu, saya dapat melihat bahwa itu memang meningkat:
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';
Hasil untuk tes khusus ini adalah sebagai berikut:
wait_type waiting_tasks_count wait_time_ms max_wait_time_ms signal_wait_time_ms TRANSACTION_MUTEX 2 181732 93899 0
Jadi saya melihat ada dua tugas yang menunggu (dua sesi yang secara bersamaan mencoba memperbarui tabel yang sama melalui loop). Karena saya belum menjalankan SET NOCOUNT ON
, saya dapat melihat bahwa hanya UPDATE
. yang dieksekusi pertama kali loop mendapat perubahan. Saya mencoba teknik serupa ini menggunakan beberapa variasi berbeda (misalnya – empat sesi keseluruhan, dengan tiga menunggu) – dan TRANSACTION_MUTEX
incrementing menunjukkan perilaku yang sama. Saya juga melihat TRANSACTION_MUTEX
akumulasi ketika secara bersamaan memperbarui tabel yang berbeda untuk setiap sesi – jadi modifikasi terhadap objek yang sama dalam satu lingkaran tidak diperlukan untuk mereproduksi TRANSACTION_MUTEX
akumulasi waktu tunggu.
Transaksi terdistribusi
Pengujian saya berikutnya melibatkan melihat apakah TRANSACTION_MUTEX
waktu tunggu bertambah untuk transaksi terdistribusi. Untuk pengujian ini, saya menggunakan dua instance SQL Server dan server tertaut yang terhubung di antara keduanya. MS DTC berjalan dan dikonfigurasi dengan benar, dan saya mengeksekusi kode berikut yang melakukan DELETE
lokal dan DELETE
remote jarak jauh melalui server tertaut dan kemudian mengembalikan perubahan:
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
tidak menunjukkan aktivitas di server lokal:
wait_type waiting_tasks_count wait_time_ms max_wait_time_ms signal_wait_time_ms TRANSACTION_MUTEX 0 0 0 0
Namun jumlah tugas menunggu bertambah di server jarak jauh:
wait_type waiting_tasks_count wait_time_ms max_wait_time_ms signal_wait_time_ms TRANSACTION_MUTEX 1 0 0 0
Jadi harapan saya untuk melihat ini dikonfirmasi – mengingat bahwa kami memiliki satu transaksi terdistribusi dengan lebih dari satu sesi yang terlibat dalam beberapa cara dengan transaksi yang sama.
MARS (Beberapa Set Hasil Aktif)
Bagaimana dengan penggunaan Multiple Active Result Sets (MARS)? Apakah kami juga berharap untuk melihat TRANSACTION_MUTEX
terakumulasi ketika dikaitkan dengan penggunaan MARS?
Untuk ini, saya menggunakan kode aplikasi konsol C# berikut yang diuji dari Microsoft Visual Studio terhadap contoh SQL Server 2012 saya dan database Kredit. Logika dari apa yang sebenarnya saya lakukan tidak terlalu berguna (mengembalikan satu baris dari setiap tabel), tetapi pembaca data berada pada koneksi yang sama dan atribut koneksi MultipleActiveResultSets
disetel ke true, jadi cukup untuk memverifikasi apakah MARS memang bisa mengemudikan TRANSACTION_MUTEX
akumulasi juga:
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]);
Setelah mengeksekusi kode ini, saya melihat akumulasi berikut untuk TRANSACTION_MUTEX
:
wait_type waiting_tasks_count wait_time_ms max_wait_time_ms signal_wait_time_ms TRANSACTION_MUTEX 8 2 0 0
Jadi seperti yang Anda lihat, aktivitas MARS (meskipun implementasinya sepele) menyebabkan peningkatan di TRANSACTION_MUTEX
akumulasi tipe tunggu. Dan atribut string koneksi itu sendiri tidak mendorong ini, implementasi sebenarnya yang melakukannya. Misalnya, saya menghapus implementasi pembaca kedua dan hanya mempertahankan satu pembaca dengan MultipleActiveResultSets=true
, dan seperti yang diharapkan, tidak ada TRANSACTION_MUTEX
akumulasi waktu tunggu.
Kesimpulan
Jika Anda melihat TRANSACTION_MUTEX
tinggi menunggu di lingkungan Anda, saya harap posting ini memberi Anda beberapa wawasan tentang tiga jalan untuk dijelajahi - untuk menentukan dari mana menunggu ini berasal, dan apakah itu perlu atau tidak.