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

TRANSACTION_MUTEX e accesso alle transazioni multisessione

Di recente ho riscontrato un elevato TRANSACTION_MUTEX tempo di attesa accumulato su un sistema client. Non riuscivo a ricordare un caso in cui ho visto questo tipo di attesa in cima all'elenco delle "attese elevate" ed ero curioso di sapere quali fattori potrebbero spingere questo tipo di tempo di attesa complessivo.

La definizione della documentazione in linea di TRANSACTION_MUTEX è che "si verifica durante la sincronizzazione dell'accesso a una transazione da più batch". Non molte aree all'interno del motore di SQL Server espongono questo tipo di funzionalità, quindi la mia indagine è stata ristretta alle seguenti tecnologie:

  • Il deprecato sp_getbindtoken e sp_bindsession procedure memorizzate di sistema utilizzate per gestire le connessioni associate
  • Transazioni distribuite
  • MARS (set di risultati attivi multipli)

Il mio obiettivo era testare ogni tecnologia e vedere se ha influenzato il TRANSACTION_MUTEX tipo di attesa.

Il primo test che ho eseguito ha utilizzato il deprecato sp_getbindtoken e sp_bindsession procedura di archiviazione. Il sp_getbindtoken restituisce un identificatore di transazione che può quindi essere utilizzato da sp_bindsession per associare più sessioni sulla stessa transazione.

Prima di ogni scenario di test, mi sono assicurato di cancellare le statistiche di attesa dell'istanza di SQL Server di test:

DBCC SQLPERF('waitstats', CLEAR);
GO

La mia istanza di prova di SQL Server eseguiva SQL Server 2012 SP1 Developer Edition (11.0.3000). Ho utilizzato il database di esempio Credit, sebbene tu possa utilizzare qualsiasi altro tipo di database di esempio come AdventureWorks se lo desideri, poiché lo schema e la distribuzione dei dati non sono direttamente pertinenti all'argomento di questo articolo e non erano necessari per guidare il TRANSACTION_MUTEX tempo di attesa.

sp_getbindtoken / sp_bindsession

Nella prima finestra di sessione di SQL Server Management Studio, ho eseguito il codice seguente per avviare una transazione e generare il token di collegamento per l'arruolamento da parte delle altre sessioni pianificate:

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

Questo ha restituito un @out_token di S/Z5_GOHLaGY<^i]S9LXZ-5---.fE--- . In due finestre di query separate di SQL Server Management Studio, ho eseguito il codice seguente per unirmi alle sessioni esistenti (accedendo alla transazione condivisa):

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

E con la prima finestra di sessione ancora aperta, ho avviato il ciclo seguente per aggiornare la tabella della tabella degli addebiti con una data di addebito uguale alla data e all'ora correnti, quindi ho eseguito la stessa logica nelle altre due finestre (tre sessioni attive nel ciclo):

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

Dopo alcuni secondi, ho annullato ogni query in esecuzione. Delle tre sessioni, solo una è stata in grado di eseguire effettivamente gli aggiornamenti, anche se le altre due sessioni sono state attivamente unite alla stessa transazione. E se guardassi il TRANSACTION_MUTEX tipo wait, posso vedere che è stato effettivamente incrementato:

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

I risultati di questo particolare test sono stati i seguenti:

wait_type            waiting_tasks_count   wait_time_ms   max_wait_time_ms   signal_wait_time_ms
TRANSACTION_MUTEX    2                     181732         93899              0

Quindi vedo che c'erano due attività in attesa (le due sessioni che stavano tentando contemporaneamente di aggiornare la stessa tabella tramite il ciclo). Dal momento che non avevo eseguito SET NOCOUNT ON , ho potuto vedere che solo il primo UPDATE eseguito loop ha apportato modifiche. Ho provato questa tecnica simile usando alcune varianti diverse (ad esempio – quattro sessioni complessive, con tre in attesa) – e il TRANSACTION_MUTEX l'incremento ha mostrato un comportamento simile. Ho visto anche il TRANSACTION_MUTEX accumulazione durante l'aggiornamento simultaneo di una tabella diversa per ogni sessione, quindi non erano necessarie modifiche allo stesso oggetto in un ciclo per riprodurre il TRANSACTION_MUTEX accumulo di tempo di attesa.

Transazioni distribuite

Il mio prossimo test consisteva nel vedere se TRANSACTION_MUTEX il tempo di attesa è stato incrementato per le transazioni distribuite. Per questo test, ho utilizzato due istanze di SQL Server e un server collegato collegato tra loro due. MS DTC era in esecuzione e configurato correttamente e ho eseguito il codice seguente che ha eseguito un DELETE locale e un DELETE remoto tramite il server collegato e quindi ripristinato le modifiche:

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;

Il TRANSACTION_MUTEX non ha mostrato attività sul server locale:

wait_type            waiting_tasks_count   wait_time_ms   max_wait_time_ms   signal_wait_time_ms
TRANSACTION_MUTEX    0                     0              0                  0

Tuttavia, il conteggio delle attività in attesa è stato incrementato sul server remoto:

wait_type            waiting_tasks_count   wait_time_ms   max_wait_time_ms   signal_wait_time_ms
TRANSACTION_MUTEX    1                     0              0                  0

Quindi la mia aspettativa di vedere questo è stata confermata, dato che abbiamo una transazione distribuita con più di una sessione coinvolta in qualche modo con la stessa transazione.

MARS (set di risultati attivi multipli)

Che dire dell'uso di Multiple Active Result Sets (MARS)? Ci aspetteremmo anche di vedere TRANSACTION_MUTEX accumulare quando associato all'utilizzo di MARS?

Per questo, ho utilizzato il seguente codice dell'applicazione console C# testato da Microsoft Visual Studio rispetto alla mia istanza di SQL Server 2012 e al database dei crediti. La logica di ciò che sto effettivamente facendo non è molto utile (restituisce una riga da ogni tabella), ma i lettori di dati sono sulla stessa connessione e l'attributo di connessione MultipleActiveResultSets è impostato su true, quindi è stato sufficiente verificare se effettivamente MARS potesse guidare TRANSACTION_MUTEX anche accumulazione:

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

Dopo aver eseguito questo codice, ho visto il seguente accumulo per TRANSACTION_MUTEX :

wait_type            waiting_tasks_count   wait_time_ms   max_wait_time_ms   signal_wait_time_ms
TRANSACTION_MUTEX    8                     2              0                  0

Quindi, come puoi vedere, l'attività MARS (comunque banalmente implementata) ha causato un aumento del TRANSACTION_MUTEX accumulo di tipo wait. E lo stesso attributo della stringa di connessione non lo guida, lo fa l'implementazione effettiva. Ad esempio, ho rimosso la seconda implementazione del lettore e ho mantenuto un singolo lettore con MultipleActiveResultSets=true e, come previsto, non c'era TRANSACTION_MUTEX accumulo di tempo di attesa.

Conclusione

Se vedi un TRANSACTION_MUTEX alto attese nel tuo ambiente, spero che questo post ti dia un'idea di tre strade da esplorare:per determinare da dove provengono queste attese e se sono necessarie o meno.


No