sql >> Database teknologi >  >> RDS >> Access

TRANSACTION_MUTEX og multi-session transaktionsadgang

Jeg stødte for nylig på høj TRANSACTION_MUTEX akkumuleret ventetid på et klientsystem. Jeg kunne ikke huske et tilfælde, hvor jeg så denne ventetype som tæt på toppen af ​​listen over "høje ventetider", og jeg var nysgerrig efter, hvilke faktorer der kunne presse denne type overordnet ventetid.

Books Online-definitionen af ​​TRANSACTION_MUTEX er, at det "opstår under synkronisering af adgang til en transaktion med flere batches." Ikke mange områder inden for SQL Server-motoren afslører denne type funktionalitet, så min undersøgelse blev indsnævret til følgende teknologier:

  • Det forældede sp_getbindtoken og sp_bindsession systemlagrede procedurer, der bruges til at håndtere bundne forbindelser
  • Distribuerede transaktioner
  • MARS (flere aktive resultatsæt)

Mit mål var at teste hver teknologi og se, om den påvirkede TRANSACTION_MUTEX vent type.

Den første test, jeg udførte, brugte den forældede sp_getbindtoken og sp_bindsession lagrede procedurer. sp_getbindtoken returnerer et transaktions-id, som derefter kan bruges af sp_bindsession at binde flere sessioner sammen på den samme transaktion.

Før hvert testscenarie sørgede jeg for at rydde min test SQL Server-forekomsts ventestatistikker:

DBCC SQLPERF('waitstats', CLEAR);
GO

Min test SQL Server-instans kørte SQL Server 2012 SP1 Developer Edition (11.0.3000). Jeg brugte kreditprøvedatabasen, selvom du kunne bruge enhver anden form for prøvedatabase som AdventureWorks, hvis du ville, da skemaet og datafordelingen ikke er direkte relevant for emnet for denne artikel og ikke var nødvendig for at køre TRANSACTION_MUTEX ventetid.

sp_getbindtoken / sp_bindsession

I det første sessionsvindue i SQL Server Management Studio udførte jeg følgende kode for at starte en transaktion og udlæse bindetokenet til optagelse af de andre planlagte sessioner:

USE Credit;
GO
 
BEGIN TRANSACTION;
 
DECLARE @out_token varchar(255);
 
EXECUTE sp_getbindtoken @out_token OUTPUT;
 
SELECT @out_token AS out_token;
GO

Dette returnerede en @out_token af S/Z5_GOHLaGY<^i]S9LXZ-5---.fE--- . I to separate SQL Server Management Studio-forespørgselsvinduer udførte jeg følgende kode for at deltage i de eksisterende sessioner (adgang til den delte transaktion):

USE Credit;
GO
 
EXEC sp_bindsession 'S/Z5_GOHLaGY<^i]S9LXZ-5---.fE---';

Og med det første sessionsvindue stadig åbent, startede jeg den følgende løkke for at opdatere ladetabellens tabel med en opladningsdato svarende til den aktuelle dato og klokkeslæt og udførte derefter den samme logik i de to andre vinduer (tre aktive sessioner i loop):

WHILE 1 = 1 
BEGIN
    UPDATE  dbo.charge
    SET     charge_dt = SYSDATETIME();
END

Efter et par sekunder annullerede jeg hver eksekverende forespørgsel. Af de tre sessioner var det kun én, der rent faktisk var i stand til at udføre opdateringer - selvom de to andre sessioner var aktivt tilsluttet den samme transaktion. Og hvis jeg så på TRANSACTION_MUTEX vent type, jeg kan se, at det faktisk steg:

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';

Resultaterne for denne særlige test var som følger:

wait_type            waiting_tasks_count   wait_time_ms   max_wait_time_ms   signal_wait_time_ms
TRANSACTION_MUTEX    2                     181732         93899              0

Så jeg kan se, at der var to ventende opgaver (de to sessioner, der samtidig forsøgte at opdatere den samme tabel via løkken). Da jeg ikke havde udført SET NOCOUNT ON , jeg kunne se, at kun den første udførte UPDATE loop fik ændringer. Jeg prøvede denne lignende teknik ved at bruge et par forskellige variationer (for eksempel – fire overordnede sessioner, med tre ventende) – og TRANSACTION_MUTEX stigende viste lignende adfærd. Jeg så også TRANSACTION_MUTEX akkumulering ved samtidig opdatering af en anden tabel for hver session – så ændringer mod det samme objekt i en loop var ikke påkrævet for at reproducere TRANSACTION_MUTEX ventetidsakkumulering.

Distribuerede transaktioner

Min næste test involverede at se, om TRANSACTION_MUTEX ventetiden blev øget for distribuerede transaktioner. Til denne test brugte jeg to SQL Server-instanser og en forbundet server forbundet mellem de to af dem. MS DTC kørte og var korrekt konfigureret, og jeg udførte følgende kode, der udførte en lokal DELETE og en ekstern DELETE via den linkede server og rullede derefter ændringerne tilbage:

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 viste ingen aktivitet på den lokale server:

wait_type            waiting_tasks_count   wait_time_ms   max_wait_time_ms   signal_wait_time_ms
TRANSACTION_MUTEX    0                     0              0                  0

Men antallet af ventende opgaver blev øget på fjernserveren:

wait_type            waiting_tasks_count   wait_time_ms   max_wait_time_ms   signal_wait_time_ms
TRANSACTION_MUTEX    1                     0              0                  0

Så min forventning om at se dette blev bekræftet – givet at vi har én distribueret transaktion med mere end én session involveret på en eller anden måde med den samme transaktion.

MARS (Flere aktive resultatsæt)

Hvad med brugen af ​​Multiple Active Result Sets (MARS)? Ville vi også forvente at se TRANSACTION_MUTEX akkumuleres, når det er forbundet med MARS-brug?

Til dette brugte jeg følgende C#-konsolapplikationskode testet fra Microsoft Visual Studio mod min SQL Server 2012-instans og Credit-databasen. Logikken i det, jeg faktisk laver, er ikke særlig nyttig (returnerer en række fra hver tabel), men datalæserne er på den samme forbindelse og forbindelsesattributten MultipleActiveResultSets er sat til sand, så det var nok til at bekræfte, om MARS faktisk kunne køre TRANSACTION_MUTEX også akkumulering:

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]);

Efter at have udført denne kode, så jeg følgende akkumulering for TRANSACTION_MUTEX :

wait_type            waiting_tasks_count   wait_time_ms   max_wait_time_ms   signal_wait_time_ms
TRANSACTION_MUTEX    8                     2              0                  0

Så som du kan se, forårsagede MARS-aktiviteten (dog trivielt implementeret) en stigning i TRANSACTION_MUTEX ventetype akkumulering. Og selve forbindelsesstrengattributten driver ikke dette, det gør den faktiske implementering. For eksempel fjernede jeg den anden læserimplementering og vedligeholdt bare en enkelt læser med MultipleActiveResultSets=true , og som forventet var der ingen TRANSACTION_MUTEX ventetidsakkumulering.

Konklusion

Hvis du ser høj TRANSACTION_MUTEX venter i dit miljø, håber jeg, at dette indlæg giver dig et indblik i tre muligheder for at udforske - for at bestemme både, hvor disse ventetider kommer fra, og om de er nødvendige eller ej.


  1. Oracles standard DATO-format

  2. Hvordan make_timestamp() virker i PostgreSQL

  3. Pad en streng med indledende nuller, så den er 3 tegn lang i SQL Server 2008

  4. TO_DSINTERVAL() Funktion i Oracle