sql >> Database >  >> RDS >> Access

TRANSACTION_MUTEX en toegang tot transacties voor meerdere sessies

Ik heb onlangs last van hoge TRANSACTION_MUTEX geaccumuleerde wachttijd op een clientsysteem. Ik kon me geen geval herinneren waarin ik dit type wachttijd bovenaan de lijst met "hoge wachttijden" zag staan ​​en ik was benieuwd welke factoren dit type algemene wachttijd zouden kunnen opdrijven.

De Books Online-definitie van TRANSACTION_MUTEX is dat het "optreedt tijdens synchronisatie van toegang tot een transactie door meerdere batches." Niet veel gebieden binnen de SQL Server-engine stellen dit soort functionaliteit bloot, dus mijn onderzoek werd beperkt tot de volgende technologieën:

  • Het verouderde sp_getbindtoken en sp_bindsession door het systeem opgeslagen procedures die worden gebruikt om gebonden verbindingen af ​​te handelen
  • Gedistribueerde transacties
  • MARS (meerdere actieve resultatensets)

Mijn doel was om elke technologie te testen en te zien of deze de TRANSACTION_MUTEX . beïnvloedde wacht type.

De eerste test die ik uitvoerde gebruikte het verouderde sp_getbindtoken en sp_bindsession opgeslagen procedures. Het sp_getbindtoken geeft een transactie-ID terug die vervolgens kan worden gebruikt door sp_bindsession om meerdere sessies samen te binden op dezelfde transactie.

Voor elk testscenario heb ik ervoor gezorgd dat de wachtstatistieken van mijn SQL Server-testinstantie zijn gewist:

DBCC SQLPERF('waitstats', CLEAR);
GO

Op mijn testexemplaar van SQL Server werd SQL Server 2012 SP1 Developer Edition (11.0.3000) uitgevoerd. Ik heb de Credit-voorbeelddatabase gebruikt, hoewel je desgewenst elk ander soort voorbeelddatabase zoals AdventureWorks kunt gebruiken, omdat het schema en de gegevensdistributie niet direct relevant zijn voor het onderwerp van dit artikel en niet nodig waren om te rijden de TRANSACTION_MUTEX wachttijd.

sp_getbindtoken / sp_bindsession

In het eerste sessievenster van SQL Server Management Studio heb ik de volgende code uitgevoerd om een ​​transactie te starten en het bindtoken uit te voeren voor aanmelding door de andere geplande sessies:

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

Dit leverde een @out_token . op van S/Z5_GOHLaGY<^i]S9LXZ-5---.fE--- . In twee afzonderlijke queryvensters van SQL Server Management Studio heb ik de volgende code uitgevoerd om deel te nemen aan de bestaande sessies (toegang tot de gedeelde transactie):

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

En met het eerste sessievenster nog steeds open, begon ik de volgende lus om de tabel van de oplaadtabel bij te werken met een oplaaddatum gelijk aan de huidige datum en tijd, en voerde vervolgens dezelfde logica uit in de andere twee vensters (drie actieve sessies in de lus):

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

Na een paar seconden heb ik elke uitvoerende query geannuleerd. Van de drie sessies was er slechts één in staat om daadwerkelijk updates uit te voeren, ook al waren de andere twee sessies actief betrokken bij dezelfde transactie. En als ik keek naar de TRANSACTION_MUTEX wacht type, ik kan zien dat het inderdaad is toegenomen:

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

De resultaten voor deze specifieke test waren als volgt:

wait_type            waiting_tasks_count   wait_time_ms   max_wait_time_ms   signal_wait_time_ms
TRANSACTION_MUTEX    2                     181732         93899              0

Dus ik zie dat er twee wachttaken waren (de twee sessies die tegelijkertijd probeerden dezelfde tabel via de lus bij te werken). Aangezien ik SET NOCOUNT ON niet had uitgevoerd , ik kon zien dat alleen de eerste uitgevoerde UPDATE loop kreeg veranderingen. Ik probeerde deze vergelijkbare techniek met een paar verschillende variaties (bijvoorbeeld – vier algemene sessies, met drie wachten) – en de TRANSACTION_MUTEX toename vertoonde vergelijkbaar gedrag. Ik zag ook de TRANSACTION_MUTEX accumulatie bij het gelijktijdig updaten van een andere tabel voor elke sessie - dus aanpassingen aan hetzelfde object in een lus waren niet nodig om de TRANSACTION_MUTEX te reproduceren wachttijd accumulatie.

Gedistribueerde transacties

Mijn volgende test was om te kijken of TRANSACTION_MUTEX wachttijd werd verhoogd voor gedistribueerde transacties. Voor deze test heb ik twee SQL Server-instanties en een gekoppelde server tussen beide gebruikt. MS DTC was actief en correct geconfigureerd, en ik voerde de volgende code uit die een lokale DELETE uitvoerde en een afstandsbediening DELETE via de gekoppelde server en vervolgens de wijzigingen teruggedraaid:

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;

De TRANSACTION_MUTEX toonde geen activiteit op de lokale server:

wait_type            waiting_tasks_count   wait_time_ms   max_wait_time_ms   signal_wait_time_ms
TRANSACTION_MUTEX    0                     0              0                  0

Het aantal wachtende taken is echter verhoogd op de externe server:

wait_type            waiting_tasks_count   wait_time_ms   max_wait_time_ms   signal_wait_time_ms
TRANSACTION_MUTEX    1                     0              0                  0

Dus mijn verwachting om dit te zien werd bevestigd - aangezien we één gedistribueerde transactie hebben met meer dan één sessie die op de een of andere manier bij dezelfde transactie betrokken is.

MARS (meerdere actieve resultatensets)

Hoe zit het met het gebruik van Multiple Active Result Sets (MARS)? Zouden we ook TRANSACTION_MUTEX . verwachten? accumuleren wanneer geassocieerd met MARS-gebruik?

Hiervoor heb ik de volgende C#-consoletoepassingscode gebruikt die is getest door Microsoft Visual Studio tegen mijn SQL Server 2012-instantie en de Credit-database. De logica van wat ik eigenlijk doe is niet erg handig (retourneert één rij van elke tabel), maar de gegevenslezers hebben dezelfde verbinding en het verbindingskenmerk MultipleActiveResultSets is ingesteld op true, dus het was voldoende om te verifiëren of MARS inderdaad TRANSACTION_MUTEX kon aansturen ook accumulatie:

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

Na het uitvoeren van deze code, zag ik de volgende accumulatie voor TRANSACTION_MUTEX :

wait_type            waiting_tasks_count   wait_time_ms   max_wait_time_ms   signal_wait_time_ms
TRANSACTION_MUTEX    8                     2              0                  0

Zoals je kunt zien, veroorzaakte de MARS-activiteit (hoe triviaal ook geïmplementeerd) een stijging in de TRANSACTION_MUTEX wacht type accumulatie. En het kenmerk van de verbindingsreeks zelf stuurt dit niet aan, de daadwerkelijke implementatie wel. Ik heb bijvoorbeeld de implementatie van de tweede lezer verwijderd en slechts één lezer behouden met MultipleActiveResultSets=true , en zoals verwacht, was er geen TRANSACTION_MUTEX wachttijd accumulatie.

Conclusie

Als u hoge TRANSACTION_MUTEX . ziet wacht in uw omgeving, ik hoop dat dit bericht u enig inzicht geeft in drie wegen die u kunt verkennen - om te bepalen waar deze wachttijden vandaan komen en of ze al dan niet nodig zijn.


  1. Hoe u uw PostgreSQL-databases kunt beschermen tegen cyberaanvallen met SQL Firewall

  2. Waarschuwing:mysqli_query():Kan mysqli niet ophalen

  3. Twee SQL LEFT JOINS produceren een onjuist resultaat

  4. Op de juiste manier samengestelde primaire sleutels maken - MYSQL