Identificare e risolvere gli errori bloccanti
Si applica a: database SQL di Azure
database SQL in Fabric
L'articolo descrive il blocco nei database SQL di Azure e SQL di Fabric, e dimostra come individuare e risolvere i problemi di blocco.
Obiettivo
In questo articolo il termine connessione fa riferimento a una singola sessione di accesso del database. Ogni connessione viene visualizzata come ID sessione (SPID) o session_id
in molte DMV. Ognuno di questi SPID viene spesso definito processo, anche se non è un contesto di processo separato nel senso consueto. Ogni SPID è invece costituito dalle risorse del server e dalle strutture di dati necessarie per gestire le richieste di una singola connessione da un determinato client. Una singola applicazione client può avere una o più connessioni. Dal punto di vista di database SQL di Azure, non esiste alcuna differenza tra più connessioni da una singola applicazione client in un singolo computer client e più connessioni da più applicazioni client o più computer client, ma sono atomiche. Una connessione può bloccarne un'altra, indipendentemente dal client di origine.
Per informazioni sulla risoluzione dei deadlock, vedere Analizzare e prevenire i deadlock in Azure SQL Database e Fabric SQL database.
Nota
Questo contenuto è incentrato sul database SQL di Azure. Database SQL di Azure si basa sulla versione stabile più recente del motore di database di Microsoft SQL Server, quindi gran parte del contenuto è simile, anche se le opzioni e gli strumenti per la risoluzione dei problemi possono differire. Per altre informazioni sui blocchi in SQL Server, vedere Comprendere e risolvere i problemi di blocco di SQL Server. Il database SQL Fabric condivide molte funzionalità con il database SQL di Azure. Per altre informazioni sul monitoraggio delle prestazioni, vedere Monitorare il database SQL in Microsoft Fabric.
Comprendere il blocco
Il blocco è una caratteristica inevitabile e di progettazione di qualsiasi sistema di gestione di database relazionali (RDBMS, Relational Database Management System) con concorrenza basata sul blocco. Il blocco in un database SQL di Azure si verifica quando una sessione mantiene un blocco su una risorsa specifica e un secondo SPID tenta di acquisire un tipo di blocco in conflitto sulla stessa risorsa. In genere, l'intervallo di tempo per il quale il primo SPID blocca la risorsa è breve. Quando la sessione rilascia il blocco di cui è proprietaria, la seconda connessione è quindi libera di acquisire il proprio blocco sulla risorsa e può continuare l'elaborazione. Questo comportamento è normale e può verificarsi molte volte durante il corso di un giorno senza effetti evidenti sulle prestazioni del sistema.
Per ogni nuovo database in Azure SQL Database è abilitata l'impostazione del database read committed snapshot (RCSI) per impostazione predefinita. Il blocco tra le sessioni che leggono i dati e quelle che scrivono i dati è ridotto sotto RCSI, che utilizza il versionamento delle righe per aumentare la concorrenza. Tuttavia, il bloccaggio e i deadlock possono verificarsi comunque nei database in database SQL di Azure perché:
- Le query che modificano i dati potrebbero bloccarsi tra loro.
- Le query possono essere eseguite con livelli di isolamento che aumentano i blocchi. I livelli di isolamento possono essere specificati nelle stringa di connessione dell'applicazione, negli hint di query o nelle istruzioni SET in Transact-SQL.
- RCSI può essere disabilitato, causando l'uso dei blocchi condivisi (S) da parte del database per proteggere le istruzioni SELECT eseguite con il livello di isolamento Read Committed. Ciò può aumentare il bloccaggio e i deadlock.
Il livello di isolamento dello snapshot è abilitato per impostazione predefinita anche per i nuovi database in database SQL di Azure. L'isolamento dello snapshot è un livello di isolamento aggiuntivo basato su righe che garantisce coerenza a livello di transazione per i dati e che usa le versioni delle righe per selezionare le righe da aggiornare. Per usare l'isolamento dello snapshot, le query o le connessioni devono impostare in modo esplicito il livello di isolamento della transazione su SNAPSHOT
. Tale operazione può essere eseguita solo quando l'isolamento dello snapshot è abilitato per il database.
È possibile identificare se l'isolamento RCSI e/o dello snapshot è abilitato con Transact-SQL. Connetti al database SQL di Azure ed esegui la query seguente:
SELECT name, is_read_committed_snapshot_on, snapshot_isolation_state_desc
FROM sys.databases
WHERE name = DB_NAME();
GO
Se è abilitato RCSI, la colonna is_read_committed_snapshot_on
restituirà il valore 1. Se è abilitato l'isolamento dello snapshot, la colonna snapshot_isolation_state_desc
restituirà il valore ON.
La durata e il contesto delle transazioni di una query determinano per quanto tempo i blocchi vengono mantenuti e l'effetto che hanno su altre query. Le istruzioni SELECT eseguite in RCSI non acquisiscono blocchi condivisi (S) sui dati letti e pertanto non bloccano le transazioni che modificano i dati. Per le istruzioni INSERT, UPDATE e DELETE, i blocchi vengono mantenuti durante la query, sia per coerenza dei dati che per consentire il rollback della query, se necessario.
Per le query eseguite all'interno di una transazione esplicita, il tipo di blocchi e la durata per cui vengono mantenuti i blocchi sono determinati dal tipo di query, dal livello di isolamento della transazione e dall'uso degli hint di blocco nella query. Per una descrizione dei livelli di blocco, hint di blocco e isolamento delle transazioni, vedere gli articoli seguenti:
- Blocchi nel motore di gestione del database
- Personalizzazione del bloccaggio e del versionamento delle righe
- Modalità di blocco
- Compatibilità del blocco
- Transazioni
Quando il blocco e il bloccaggio vengono mantenuti fino al punto in cui si verifica un effetto negativo sulle prestazioni del sistema, è dovuto a uno dei motivi seguenti:
Uno SPID mantiene blocchi su un set di risorse per un periodo di tempo prolungato prima di rilasciarli. Questo tipo di bloccaggio si risolve nel tempo, ma può causare una riduzione delle prestazioni.
Uno SPID mantiene blocchi su un set di risorse senza mai rilasciarli. Questo tipo di bloccaggio non si risolve e impedisce l'accesso alle risorse interessate a tempo indeterminato.
Nel primo scenario, la situazione può essere molto fluida mentre diversi SPID causano il blocco di risorse diverse nel tempo, creando un bersaglio mobile. Queste situazioni sono difficili da risolvere usando SQL Server Management Studio per limitare il problema alle singole query. Al contrario, la seconda situazione comporta uno stato coerente che può essere più facile da diagnosticare.
Blocco ottimizzato
Il blocco ottimizzato è una nuova funzionalità di motore di database che riduce drasticamente la memoria di blocco e il numero di blocchi necessari simultaneamente per le scritture. Il blocco ottimizzato utilizza due componenti principali: il blocco dell'ID transazione (TID), utilizzato anche in altre funzionalità di controllo delle versioni delle righe, e il blocco dopo la qualificazione (LAQ). Non richiede alcuna configurazione aggiuntiva.
Questo articolo si applica attualmente al comportamento del motore di database senza blocchi ottimizzati.
Per altre informazioni e per informazioni su dove è disponibile il blocco ottimizzato, vedere Blocco ottimizzato.
Applicazioni e blocco
Potrebbe esserci una tendenza a concentrarsi sull'ottimizzazione lato server e sui problemi della piattaforma quando si riscontra un problema di blocco. Tuttavia, l'attenzione prestata solo al database potrebbe non causare una risoluzione e può assorbire il tempo e l'energia meglio indirizzati all'analisi dell'applicazione client e alle query inviate. Indipendentemente dal livello di visibilità esposto dall'applicazione per quanto riguarda le chiamate di database effettuate, un problema di blocco richiede spesso sia l'ispezione delle istruzioni SQL esatte inviate dall'applicazione, sia il comportamento esatto dell'applicazione relativo all'annullamento delle query, alla gestione della connessione, al recupero di tutte le righe dei risultati e così via. Se lo strumento di sviluppo non consente il controllo esplicito sulla gestione delle connessioni, l'annullamento delle query, il timeout delle query, il recupero dei risultati e così via, i problemi di blocco potrebbero non essere risolvibili. Questo potenziale deve essere esaminato attentamente prima di selezionare uno strumento di sviluppo di applicazioni per database SQL di Azure, in particolare per gli ambienti OLTP sensibili alle prestazioni.
Prestare attenzione alle prestazioni del database durante la fase di progettazione e costruzione del database e dell'applicazione. In particolare, il consumo delle risorse, il livello di isolamento e la lunghezza del percorso delle transazioni devono essere valutati per ogni query. Le query e le transazioni devono essere il più leggere possibile. Una buona disciplina di gestione delle connessioni deve essere esercitata. Senza di esso, l'applicazione può sembrare avere prestazioni accettabili a un numero ridotto di utenti, ma le prestazioni potrebbero peggiorare significativamente man mano che il numero di utenti aumenta.
Con una progettazione corretta di applicazioni e query, database SQL di Azure è in grado di supportare molte migliaia di utenti simultanei in un singolo server, con poco blocco.
Nota
Per altre indicazioni sullo sviluppo di applicazioni, vedere Risolvere i problemi di connettività e altri errori e gestione degli errori temporanei.
Risolvere i problemi di blocco
Indipendentemente dalla situazione di blocco in cui ci troviamo, la metodologia per la risoluzione dei problemi di blocco è la stessa. Queste separazioni logiche sono ciò che determina il resto della composizione di questo articolo. Il concetto consiste nel trovare il blocco principale e identificare cosa fa la query e perché sta bloccando. Una volta identificata la query problematica, ovvero ciò che mantiene i blocchi per il periodo prolungato, il passaggio successivo consiste nell'analizzare e determinare il motivo per cui si sta verificando il blocco. Dopo aver compreso i motivi per cui è possibile apportare modifiche, è possibile riprogettare la query e la transazione.
Procedura per la risoluzione dei problemi:
Identificare la sessione di blocco principale (blocco testa)
Trovare la query e la transazione che causano il blocco (che contiene blocchi per un periodo prolungato)
Analizzare/comprendere perché si verifica il blocco prolungato
Risolvere il problema di bloccaggio riprogettando query e transazioni
Si esaminerà ora come individuare la sessione di blocco principale con un'acquisizione dei dati appropriata.
Raccolta di informazioni sul bloccaggio
Per contrastare la difficoltà di risoluzione dei problemi di blocco, un amministratore di database può usare script SQL che monitorano costantemente lo stato di blocco e blocco nel database in database SQL di Azure. Per raccogliere questi dati, esistono essenzialmente due metodi.
Il primo consiste nell'eseguire query sugli oggetti a gestione dinamica (DMO) e archiviare i risultati per il confronto nel tempo. Alcuni oggetti a cui si fa riferimento in questo articolo sono DMV e alcune sono funzioni a gestione dinamica (DMF). Il secondo metodo consiste nell'usare XEvents per acquisire ciò che viene eseguito.
Raccogli informazioni dalle DMV
Fare riferimento alle DMV per risolvere i problemi di blocco ha l'obiettivo di identificare lo SPID (ID sessione) all'inizio della catena di blocco e dell'istruzione SQL. Cerca gli SPID delle vittime che vengono bloccati. Se uno SPID è bloccato da un altro SPID, analizzare lo SPID proprietario della risorsa (SPID bloccante). Anche il proprietario di SPID è bloccato? È possibile esaminare la catena per trovare il blocco principale e quindi indagare sul perché sta mantenendo il suo blocco.
Ricordarsi di eseguire ognuno di questi script nel database di destinazione in database SQL di Azure.
I comandi
sp_who
esp_who2
sono comandi meno recenti per visualizzare tutte le sessioni correnti. La DMVsys.dm_exec_sessions
restituisce più dati in un set di risultati più semplice da eseguire query e filtrare. È possibile trovaresys.dm_exec_sessions
alla base di altre query.Se è già stata identificata una sessione specifica, è possibile usare
DBCC INPUTBUFFER(<session_id>)
per trovare l'ultima istruzione inviata da una sessione. I risultati simili possono essere restituiti con la funzione a gestione dinamica (DMF)sys.dm_exec_input_buffer
, in un set di risultati più semplice da eseguire query e filtrare, fornendo il session_id e il request_id. Ad esempio, per restituire la query più recente inviata da session_id 66 e request_id 0:
SELECT * FROM sys.dm_exec_input_buffer (66,0);
Fare riferimento alla colonna
blocking_session_id
insys.dm_exec_requests
. Quandoblocking_session_id
= 0, una sessione non viene bloccata. Mentresys.dm_exec_requests
elenca solo le richieste attualmente in esecuzione, qualsiasi connessione (attiva o meno) viene elencata insys.dm_exec_sessions
. Creare questo join comune trasys.dm_exec_requests
esys.dm_exec_sessions
nella query successiva.Eseguire questa query di esempio per trovare le query in esecuzione attivamente e il testo corrente del batch SQL o del buffer di input, usando le DMV sys.dm_exec_sql_text o sys.dm_exec_input_buffer. Se i dati restituiti dal campo
text
disys.dm_exec_sql_text
sono NULL, la query non è attualmente in esecuzione. In tal caso, il campoevent_info
contiene l'ultima stringa di comandosys.dm_exec_input_buffer
passata al motore SQL. Questa query può essere utilizzata anche per identificare le sessioni che bloccano altre sessioni, compreso un elenco di session_ids bloccati per session_id.
WITH cteBL (session_id, blocking_these) AS
(SELECT s.session_id, blocking_these = x.blocking_these FROM sys.dm_exec_sessions s
CROSS APPLY (SELECT isnull(convert(varchar(6), er.session_id),'') + ', '
FROM sys.dm_exec_requests as er
WHERE er.blocking_session_id = isnull(s.session_id ,0)
AND er.blocking_session_id <> 0
FOR XML PATH('') ) AS x (blocking_these)
)
SELECT s.session_id, blocked_by = r.blocking_session_id, bl.blocking_these
, batch_text = t.text, input_buffer = ib.event_info, *
FROM sys.dm_exec_sessions s
LEFT OUTER JOIN sys.dm_exec_requests r on r.session_id = s.session_id
INNER JOIN cteBL as bl on s.session_id = bl.session_id
OUTER APPLY sys.dm_exec_sql_text (r.sql_handle) t
OUTER APPLY sys.dm_exec_input_buffer(s.session_id, NULL) AS ib
WHERE blocking_these is not null or r.blocking_session_id > 0
ORDER BY len(bl.blocking_these) desc, r.blocking_session_id desc, r.session_id;
- Esegui questa query di esempio più elaborata, fornita dal Supporto Tecnico Microsoft, per identificare il nodo di una catena di blocco multipla, incluso il testo della query delle sessioni coinvolte.
WITH cteHead ( session_id,request_id,wait_type,wait_resource,last_wait_type,is_user_process,request_cpu_time
,request_logical_reads,request_reads,request_writes,wait_time,blocking_session_id,memory_usage
,session_cpu_time,session_reads,session_writes,session_logical_reads
,percent_complete,est_completion_time,request_start_time,request_status,command
,plan_handle,sql_handle,statement_start_offset,statement_end_offset,most_recent_sql_handle
,session_status,group_id,query_hash,query_plan_hash)
AS ( SELECT sess.session_id, req.request_id, LEFT (ISNULL (req.wait_type, ''), 50) AS 'wait_type'
, LEFT (ISNULL (req.wait_resource, ''), 40) AS 'wait_resource', LEFT (req.last_wait_type, 50) AS 'last_wait_type'
, sess.is_user_process, req.cpu_time AS 'request_cpu_time', req.logical_reads AS 'request_logical_reads'
, req.reads AS 'request_reads', req.writes AS 'request_writes', req.wait_time, req.blocking_session_id,sess.memory_usage
, sess.cpu_time AS 'session_cpu_time', sess.reads AS 'session_reads', sess.writes AS 'session_writes', sess.logical_reads AS 'session_logical_reads'
, CONVERT (decimal(5,2), req.percent_complete) AS 'percent_complete', req.estimated_completion_time AS 'est_completion_time'
, req.start_time AS 'request_start_time', LEFT (req.status, 15) AS 'request_status', req.command
, req.plan_handle, req.[sql_handle], req.statement_start_offset, req.statement_end_offset, conn.most_recent_sql_handle
, LEFT (sess.status, 15) AS 'session_status', sess.group_id, req.query_hash, req.query_plan_hash
FROM sys.dm_exec_sessions AS sess
LEFT OUTER JOIN sys.dm_exec_requests AS req ON sess.session_id = req.session_id
LEFT OUTER JOIN sys.dm_exec_connections AS conn on conn.session_id = sess.session_id
)
, cteBlockingHierarchy (head_blocker_session_id, session_id, blocking_session_id, wait_type, wait_duration_ms,
wait_resource, statement_start_offset, statement_end_offset, plan_handle, sql_handle, most_recent_sql_handle, [Level])
AS ( SELECT head.session_id AS head_blocker_session_id, head.session_id AS session_id, head.blocking_session_id
, head.wait_type, head.wait_time, head.wait_resource, head.statement_start_offset, head.statement_end_offset
, head.plan_handle, head.sql_handle, head.most_recent_sql_handle, 0 AS [Level]
FROM cteHead AS head
WHERE (head.blocking_session_id IS NULL OR head.blocking_session_id = 0)
AND head.session_id IN (SELECT DISTINCT blocking_session_id FROM cteHead WHERE blocking_session_id != 0)
UNION ALL
SELECT h.head_blocker_session_id, blocked.session_id, blocked.blocking_session_id, blocked.wait_type,
blocked.wait_time, blocked.wait_resource, h.statement_start_offset, h.statement_end_offset,
h.plan_handle, h.sql_handle, h.most_recent_sql_handle, [Level] + 1
FROM cteHead AS blocked
INNER JOIN cteBlockingHierarchy AS h ON h.session_id = blocked.blocking_session_id and h.session_id!=blocked.session_id --avoid infinite recursion for latch type of blocking
WHERE h.wait_type COLLATE Latin1_General_BIN NOT IN ('EXCHANGE', 'CXPACKET') or h.wait_type is null
)
SELECT bh.*, txt.text AS blocker_query_or_most_recent_query
FROM cteBlockingHierarchy AS bh
OUTER APPLY sys.dm_exec_sql_text (ISNULL ([sql_handle], most_recent_sql_handle)) AS txt;
- Per intercettare transazioni a esecuzione prolungata o di cui non è stato eseguito il commit, usare un altro set di DMV per visualizzare le transazioni aperte correnti, tra cui sys.dm_tran_database_transactions, sys.dm_tran_session_transactions, sys.dm_exec_connections e sys.dm_exec_sql_text. Esistono diverse DMV associate al monitoraggio delle transazioni, consultare le viste e le funzioni di gestione dinamica correlate alle transazioni per ulteriori informazioni.
SELECT [s_tst].[session_id],
[database_name] = DB_NAME (s_tdt.database_id),
[s_tdt].[database_transaction_begin_time],
[sql_text] = [s_est].[text]
FROM sys.dm_tran_database_transactions [s_tdt]
INNER JOIN sys.dm_tran_session_transactions [s_tst] ON [s_tst].[transaction_id] = [s_tdt].[transaction_id]
INNER JOIN sys.dm_exec_connections [s_ec] ON [s_ec].[session_id] = [s_tst].[session_id]
CROSS APPLY sys.dm_exec_sql_text ([s_ec].[most_recent_sql_handle]) AS [s_est];
- Riferimento sys.dm_os_waiting_tasks che si trova al livello di thread/attività di SQL. Vengono restituite informazioni sul tipo di attesa SQL attualmente riscontrato dalla richiesta. Come
sys.dm_exec_requests
, solo le richieste attive vengono restituite dasys.dm_os_waiting_tasks
.
Nota
Per altre informazioni sui tipi di attesa, incluse le statistiche di attesa aggregate nel tempo, vedere la DMV sys.dm_db_wait_stats. Questa DMV restituisce statistiche di attesa aggregate solo per il database corrente.
- Per ottenere informazioni più granulari sui blocchi inseriti dalle query, usare la DMV sys.dm_tran_locks. Questa DMV può restituire grandi quantità di dati in un database di produzione ed è utile per diagnosticare i blocchi attualmente mantenuti.
A causa dell’INNER JOIN su sys.dm_os_waiting_tasks
, la query seguente limita l'output da sys.dm_tran_locks
solo alle richieste attualmente bloccate, al relativo stato di attesa e ai relativi blocchi:
SELECT table_name = schema_name(o.schema_id) + '.' + o.name
, wt.wait_duration_ms, wt.wait_type, wt.blocking_session_id, wt.resource_description
, tm.resource_type, tm.request_status, tm.request_mode, tm.request_session_id
FROM sys.dm_tran_locks AS tm
INNER JOIN sys.dm_os_waiting_tasks as wt ON tm.lock_owner_address = wt.resource_address
LEFT OUTER JOIN sys.partitions AS p on p.hobt_id = tm.resource_associated_entity_id
LEFT OUTER JOIN sys.objects o on o.object_id = p.object_id or tm.resource_associated_entity_id = o.object_id
WHERE resource_database_id = DB_ID()
AND object_name(p.object_id) = '<table_name>';
- Con le DMV, l'archiviazione dei risultati della query nel tempo fornisce punti dati che consentono di esaminare il blocco in un intervallo di tempo specificato per identificare tendenze o blocchi persistenti.
Raccogliere informazioni dagli eventi estesi
Oltre alle informazioni precedenti, è spesso necessario acquisire una traccia delle attività nel server per analizzare attentamente un problema di blocco in database SQL di Azure. Ad esempio, se una sessione esegue più istruzioni all'interno di una transazione, viene rappresentata solo l'ultima istruzione inviata. Tuttavia, una delle affermazioni precedenti potrebbe essere il motivo per cui i blocchi sono ancora in corso. Una traccia consentirà di visualizzare tutti i comandi eseguiti da una sessione all'interno della transazione corrente.
Esistono due modi per acquisire tracce in SQL Server: Eventi estesi (XEvent) e tracce profiler. SQL Server Profiler, tuttavia, è una tecnologia di traccia deprecata e non supportata per il database SQL di Azure. gli eventi estesi è la tecnologia di traccia più recente che consente maggiore versatilità e minore effetto sul sistema osservato e la relativa interfaccia è integrata in SQL Server Management Studio (SSMS).
Consultare il documento che illustra come usare la Creazione guidata per una nuova sessione di Eventi Estesi in SSMS. Per i database SQL di Azure, tuttavia, SSMS fornisce una sottocartella Eventi estesi in ogni database in Esplora oggetti. Usare una sessione guidata di Extended Events per acquisire questi eventi utili:
Errori di categoria
- Attenzione
- Errore_segnalato
- Avviso_di_esecuzione
Avvisi categoria:
- Predicato_di_join_mancante
Categoria esecuzione:
- Rpc_completed
- Rpc_starting
- Batch_sql_completato
- Sql_batch_starting
Categoria Monitoraggio delle Interruzioni
- rapporto_di_impasse_di_database_xml
Categoria della sessione
- Connessione_esistente
- Account di accesso
- Disconnessione
Nota
Per informazioni dettagliate sui deadlock, vedere Analizzare e prevenire deadlock nel database SQL di Azure e nel database SQL dell'infrastruttura.
Identificare e risolvere scenari di blocco comuni
Esaminando le informazioni precedenti, è possibile determinare la causa della maggior parte dei problemi di blocco. Il resto di questo articolo illustra come usare queste informazioni per identificare e risolvere alcuni scenari di blocco comuni. Questa discussione presuppone che siano stati usati gli script di blocco (a cui si fa riferimento in precedenza) per acquisire informazioni sugli SPID di blocco e che l'attività dell'applicazione sia stata acquisita usando una sessione XEvent.
Analizzare i dati bloccanti
Esaminare l'output delle DMV
sys.dm_exec_requests
esys.dm_exec_sessions
per determinare le teste delle catene di blocco, utilizzandoblocking_these
esession_id
. Ciò identifica in modo più chiaro quali richieste vengono bloccate e quali bloccano. Esaminare ulteriormente le sessioni bloccate e bloccanti. C'è una radice comune nella catena di blocco? Probabilmente condividono una tabella comune e una o più sessioni coinvolte in una catena di blocco eseguono un'operazione di scrittura.Esaminare l'output delle DMVs
sys.dm_exec_requests
esys.dm_exec_sessions
per informazioni sugli SPIDs all'inizio della catena di blocco. Cercare i seguenti campi:sys.dm_exec_requests.status
Questa colonna mostra lo stato di una determinata richiesta. In genere, uno stato di sospensione indica che lo SPID ha completato l'esecuzione ed è in attesa che l'applicazione invii un'altra query o batch. Uno stato pronto per l'esecuzione o in esecuzione indica che lo SPID sta attualmente elaborando una query. Nella tabella seguente vengono fornite brevi spiegazioni dei vari valori di stato.
Status Significato Background Lo SPID esegue un'attività in background, ad esempio il rilevamento dei blocchi, lo scrittore di log o il checkpoint. Dormire Lo SPID non è attualmente in esecuzione. Questo indica in genere che lo SPID è in attesa di un comando dall'applicazione. In esecuzione Lo SPID è attualmente in esecuzione su un pianificatore. Eseguibile Lo SPID si trova nella coda eseguibile di uno scheduler ed è in attesa di ottenere il tempo dello scheduler. Sospeso Lo SPID è in attesa di una risorsa, ad esempio un blocco o un latch. sys.dm_exec_sessions.open_transaction_count
Questo campo indica il numero di transazioni aperte in questa sessione. Se questo valore è maggiore di 0, lo SPID si trova all'interno di una transazione aperta e può contenere blocchi acquisiti da qualsiasi istruzione all'interno della transazione.sys.dm_exec_requests.open_transaction_count
Analogamente, questo campo indica il numero di transazioni aperte in questa richiesta. Se questo valore è maggiore di 0, lo SPID si trova all'interno di una transazione aperta e può contenere blocchi acquisiti da qualsiasi istruzione all'interno della transazione.sys.dm_exec_requests.wait_type
,wait_time
elast_wait_type
Sesys.dm_exec_requests.wait_type
è NULL, la richiesta non è attualmente in attesa di alcun elemento e il valorelast_wait_type
indica l'ultimowait_type
rilevato dalla richiesta. Per altre informazioni susys.dm_os_wait_stats
e una descrizione dei tipi di attesa più comuni, vedere sys.dm_os_wait_stats. Il valorewait_time
può essere usato per determinare se la richiesta sta progredendo. Quando una query sulla tabellasys.dm_exec_requests
restituisce un valore nella colonnawait_time
minore del valorewait_time
di una query precedente disys.dm_exec_requests
, indica che il blocco precedente è stato acquisito e rilasciato ed è ora in attesa di un nuovo blocco (presupponendo chewait_time
sia diverso da zero). Questa operazione si può verificare confrontando l'uscitawait_resource
trasys.dm_exec_requests
, che visualizza la risorsa in attesa di cui è la richiesta.sys.dm_exec_requests.wait_resource
Questo campo indica la risorsa in cui è in attesa una richiesta bloccata. La tabella seguente elenca i formatiwait_resource
comuni e il loro significato:
Conto risorse Formato Esempio Spiegazione Tabella DatabaseID:ObjectID:IndexID SCHEDA: 5:261575970:1 In questo caso, l'ID database 5 è il database di esempio pubs e l'ID oggetto 261575970 è la tabella dei titoli e 1 è l'indice cluster. Pagina DatabaseID:FileID:PageID PAGINA: 5:1:104 In questo caso, l'ID database 5 is pubs
, l'ID file 1 è il file di dati primario e la pagina 104 è una pagina appartenente alla tabella dei titoli. Per identificare ilobject_id
a cui appartiene la pagina, usare la funzione di gestione dinamica sys.dm_db_page_info, passando databaseID, FileId, PageId dalwait_resource
.Chiave DatabaseID:Hobt_id (valore hash per la chiave di indice) CHIAVE: 5:72057594044284928 (3300a4f361aa) In questo caso, l'ID database 5 è pubs
eHobt_ID
72057594044284928 corrisponde aindex_id
2 perobject_id
261575970 (tabella dei titoli). Utilizzare la vista del catalogosys.partitions
per associare l'hobt_id
a un determinatoindex_id
eobject_id
. Non è possibile annullare l'hash della chiave di indice in un valore di chiave specifico.Riga DatabaseID:FileID:PageID:Slot(row) RID: 5:1:104:3 In questo caso, l'ID database 5 è pubs
, l'ID file 1 è il file di dati primario, la pagina 104 è una pagina appartenente alla tabella dei titoli e lo slot 3 indica la posizione della riga nella pagina.Compila DatabaseID:FileID:PageID:Slot(row) RID: 5:1:104:3 In questo caso, l'ID database 5 è pubs
, l'ID file 1 è il file di dati primario, la pagina 104 è una pagina appartenente alla tabella dei titoli e lo slot 3 indica la posizione della riga nella pagina.-
sys.dm_tran_active_transactions
La DMV sys.dm_tran_active_transactions contiene dati sulle transazioni aperte che possono essere unite ad altre DMV per un quadro completo delle transazioni in attesa del commit o del ripristino dello stato precedente. Usare la query seguente per restituire informazioni sulle transazioni aperte, unite ad altre DMV, tra cui sys.dm_tran_session_transactions. Considerare lo stato corrente di una transazione,transaction_begin_time
, e altri dati situazionali per valutare se potrebbero essere l'origine del blocco.
SELECT tst.session_id, [database_name] = db_name(s.database_id) , tat.transaction_begin_time , transaction_duration_s = datediff(s, tat.transaction_begin_time, sysdatetime()) , transaction_type = CASE tat.transaction_type WHEN 1 THEN 'Read/write transaction' WHEN 2 THEN 'Read-only transaction' WHEN 3 THEN 'System transaction' WHEN 4 THEN 'Distributed transaction' END , input_buffer = ib.event_info, tat.transaction_uow , transaction_state = CASE tat.transaction_state WHEN 0 THEN 'The transaction has not been completely initialized yet.' WHEN 1 THEN 'The transaction has been initialized but has not started.' WHEN 2 THEN 'The transaction is active - has not been committed or rolled back.' WHEN 3 THEN 'The transaction has ended. This is used for read-only transactions.' WHEN 4 THEN 'The commit process has been initiated on the distributed transaction.' WHEN 5 THEN 'The transaction is in a prepared state and waiting resolution.' WHEN 6 THEN 'The transaction has been committed.' WHEN 7 THEN 'The transaction is being rolled back.' WHEN 8 THEN 'The transaction has been rolled back.' END , transaction_name = tat.name, request_status = r.status , azure_dtc_state = CASE tat.dtc_state WHEN 1 THEN 'ACTIVE' WHEN 2 THEN 'PREPARED' WHEN 3 THEN 'COMMITTED' WHEN 4 THEN 'ABORTED' WHEN 5 THEN 'RECOVERED' END , tst.is_user_transaction, tst.is_local , session_open_transaction_count = tst.open_transaction_count , s.host_name, s.program_name, s.client_interface_name, s.login_name, s.is_user_process FROM sys.dm_tran_active_transactions tat INNER JOIN sys.dm_tran_session_transactions tst on tat.transaction_id = tst.transaction_id INNER JOIN sys.dm_exec_sessions s on s.session_id = tst.session_id LEFT OUTER JOIN sys.dm_exec_requests r on r.session_id = s.session_id CROSS APPLY sys.dm_exec_input_buffer(s.session_id, null) AS ib;
Altre colonne
Anche le colonne rimanenti in sys.dm_exec_sessions e sys.dm_exec_request possono fornire informazioni dettagliate sulla radice di un problema. La loro utilità varia a seconda delle circostanze del problema. Ad esempio, è possibile determinare se il problema si verifica solo da determinati client (nome host), in determinate librerie di rete (net_library), quando l'ultimo batch inviato da uno SPID era
last_request_start_time
insys.dm_exec_sessions
, per quanto tempo una richiesta era in esecuzione usandostart_time
insys.dm_exec_requests
e così via.
Scenari di bloccaggio comuni
La tabella seguente esegue il mapping dei sintomi comuni alle loro probabili cause.
Le colonne Waittype
, Open_Tran
e Status
fanno riferimento alle informazioni restituite da sys.dm_exec_request. Altre colonne potrebbero essere restituite da sys.dm_exec_sessions. La colonna "Resolves?" indica se il blocco viene risolto autonomamente o se la sessione deve essere terminata tramite il comando KILL
. Per altre informazioni, vedere KILL.
Scenario | Tipo di Attesa | Open_tran | Status | Risolto? | Altri sintomi |
---|---|---|---|---|---|
1 | NON NULLO | >= 0 | eseguibile | Sì, al termine dell'interrogazione. | Nelle colonne sys.dm_exec_sessions , reads , cpu_time e/o memory_usage , l'aumento avviene nel tempo. La durata della query è elevata quando viene completata. |
2 | NULL | >0 | dormire | No, ma lo SPID può essere disattivato. | Un segnale di attenzione può essere visualizzato nella sessione degli eventi estesi per questo SPID, a indicare che si è verificato un timeout o un annullamento della query. |
3 | NULL | >= 0 | eseguibile | No. Non viene risolto finché il client non recupera tutte le righe o chiude la connessione. Lo SPID può essere terminato, ma può richiedere fino a 30 secondi. | Se open_transaction_count = 0 e lo SPID mantiene i blocchi mentre il livello di isolamento della transazione è predefinito (READ COMMITTED), questo rappresenta una causa probabile. |
4 | Variabile | >= 0 | eseguibile | No. Non viene risolto fino a quando il client non annulla le query o chiude le connessioni. Gli SPID possono essere terminati, ma ciò potrebbe richiedere fino a 30 secondi. | La colonna hostname in sys.dm_exec_sessions per l'SPID a capo di una catena di blocco è la stessa di uno degli SPID che blocca. |
5 | NULL | >0 | ripristino | Sì. | Un segnale di attenzione può essere visualizzato nella sessione Eventi estesi per questo SPID, indicando che si è verificato un timeout o un annullamento della query oppure che è stata semplicemente emessa un'istruzione di rollback. |
6 | NULL | >0 | dormire | Eventualmente. Quando Windows determina che la sessione non è più attiva, la connessione al database SQL di Azure viene interrotta. | Il valore last_request_start_time in sys.dm_exec_sessions risale a molto tempo prima rispetto all'ora corrente. |
Scenari di blocco dettagliati
Blocco causato da una query che si esegue normalmente con un tempo di esecuzione lungo
Soluzione: La soluzione per questo tipo di problema di blocco consiste nel cercare modi per ottimizzare la query. In realtà, questa classe di problema di blocco può essere solo un problema di prestazioni e richiede di seguirla come tale. Per informazioni su come risolvere i problemi relativi a una query a esecuzione lenta, consultare la sezione Risolvere i problemi relativi alle query a esecuzione lenta in SQL Server. Per altre informazioni, vedere Monitorare e ottimizzare le prestazioni.
I report di Query Store in SSMS sono anche uno strumento estremamente consigliato e prezioso per identificare le query più costose, piani di esecuzione non ottimali. Esaminare anche Approfondimenti sulle Prestazioni delle Query.
Se la query esegue solo operazioni SELECT, è consigliabile eseguire l'istruzione con isolamento dello snapshot se è abilitata nel database, soprattutto se RCSI è stato disabilitato. Come quando RCSI è abilitato, le query che leggono i dati non richiedono blocchi condivisi (S) sotto il livello di isolamento dello snapshot. Inoltre, l'isolamento dello snapshot fornisce la coerenza a livello di transazione per tutte le istruzioni in una transazione esplicita con più istruzioni. L'isolamento dello snapshot potrebbe essere già abilitato nel database. L'isolamento dello snapshot può essere usato anche con le query che eseguono modifiche, ma è necessario gestire i conflitti di aggiornamento.
Nel caso di una query a esecuzione prolungata che blocca altri utenti e non può essere ottimizzata, è consigliabile spostarla da un ambiente OLTP a un sistema di reporting dedicato, una replica sincrona di sola lettura del database.
Bloccaggio causato da un SPID dormiente con una transazione non confermata
Questo tipo di bloccaggio può spesso essere identificato da uno SPID in sospensione o in attesa di un comando, ma il cui livello di annidamento delle transazioni (
@@TRANCOUNT
,open_transaction_count
insys.dm_exec_requests
) è maggiore di zero. Ciò può verificarsi se l'applicazione riscontra un timeout delle query o genera un annullamento senza emettere anche il numero necessario di istruzioni ROLLBACK e/o COMMIT. Quando un SPID riceve un timeout della richiesta o una cancellazione, termina la query e il batch corrente, ma non esegue automaticamente il rollback o il commit della transazione. L'applicazione è responsabile di queste operazioni, perché Database SQL di Azure non può presumere che debba essere eseguito il rollback di un'intera transazione a causa dell'annullamento di una singola query. Il timeout o l'annullamento della query viene visualizzato come evento di segnale ATTENTION per SPID nella sessione di eventi estesi.Per illustrare una transazione esplicita di cui non è stato eseguito il commit, eseguire la query seguente:
CREATE TABLE #test (col1 INT); INSERT INTO #test SELECT 1; BEGIN TRAN UPDATE #test SET col1 = 2 where col1 = 1;
Eseguire quindi questa query nella stessa finestra:
SELECT @@TRANCOUNT; ROLLBACK TRAN DROP TABLE #test;
L'output della seconda query indica che il livello di annidamento della transazione è uno. Tutti i blocchi acquisiti nella transazione rimangono acquisiti fino a quando la transazione non viene eseguita o annullata. Se le applicazioni aprono ed eseguono il commit in modo esplicito delle transazioni, una comunicazione o un altro errore potrebbero lasciare la sessione e la relativa transazione in uno stato aperto.
Usare lo script riportato in precedenza in questo articolo in base a
sys.dm_tran_active_transactions
per identificare le transazioni attualmente non sottoposte a commit nell'istanza.Risoluzioni:
Inoltre, questa classe di problema di blocco può anche essere un problema di prestazioni e richiede di seguirla come tale. Se il tempo di esecuzione della query può essere ridotto, il timeout o l'annullamento della query non si verificherà. È importante che l'applicazione sia in grado di gestire gli scenari di timeout o annullamento, ma può anche trarre vantaggio dall'analisi delle prestazioni della query.
Le applicazioni devono gestire correttamente i livelli di annidamento delle transazioni oppure possono causare un problema di blocco dopo l'annullamento della query in questo modo. Considerare:
- Nel gestore degli errori dell'applicazione client eseguire
IF @@TRANCOUNT > 0 ROLLBACK TRAN
in seguito a qualsiasi errore, anche se l'applicazione client non ritiene che una transazione sia aperta. È necessario verificare la presenza di transazioni aperte, perché una stored procedure chiamata durante il batch potrebbe aver avviato una transazione senza che l'applicazione client sia a conoscenza. Alcune condizioni, ad esempio l'annullamento della query, impediscono l'esecuzione della routine oltre l'istruzione corrente, quindi anche se la routine ha la logica per controllareIF @@ERROR <> 0
e interrompere la transazione, questo codice di rollback non viene eseguito in tali casi. - Se il pool di connessioni viene usato in un'applicazione che apre la connessione ed esegue alcune query prima di rilasciare nuovamente la connessione al pool, ad esempio un'applicazione basata sul Web, la disabilitazione temporanea del pool di connessioni potrebbe contribuire ad alleviare il problema fino a quando l'applicazione client non viene modificata per gestire gli errori in modo appropriato. Disabilitando il pool di connessioni, il rilascio della connessione provoca una disconnessione fisica dal database SQL di Azure, portando il server ad eseguire il rollback delle transazioni aperte.
- Utilizzare
SET XACT_ABORT ON
per la connessione, oppure in tutte le stored procedure che iniziano le transazioni e non vengono ripulite dopo un errore. In caso di errore di run-time, questa impostazione interrompe le transazioni aperte e restituirà il controllo al client. Per ulteriori informazioni, consultare SET XACT_ABORT.
- Nel gestore degli errori dell'applicazione client eseguire
Nota
La connessione non viene reimpostata finché non viene riutilizzata dal pool di connessioni, quindi è possibile che un utente possa aprire una transazione e quindi rilasciare la connessione al pool di connessioni, ma potrebbe non essere riutilizzata per diversi secondi, durante la quale la transazione rimarrà aperta. Se la connessione non viene riutilizzata, la transazione viene interrotta quando si verifica il timeout della connessione e viene rimossa dal pool di connessioni. Pertanto, è ottimale per l'applicazione client interrompere le transazioni nel gestore errori o usare
SET XACT_ABORT ON
per evitare questo potenziale ritardo.Attenzione
Dopo
SET XACT_ABORT ON
, le istruzioni T-SQL che seguono un'istruzione che causa un errore non vengono eseguite. Ciò potrebbe influire sul flusso previsto del codice esistente.Blocco causato da uno SPID la cui applicazione client corrispondente non ha completato il recupero di tutte le righe di risultati.
Dopo aver inviato una query al server, tutte le applicazioni devono recuperare immediatamente tutte le righe di risultati al completamento. Se un'applicazione non recupera tutte le righe dei risultati, è possibile che vengano lasciati blocchi sulle tabelle, bloccando altri utenti. Se si usa un'applicazione che invia in modo trasparente istruzioni SQL al server, l'applicazione deve recuperare tutte le righe dei risultati. Se ciò non accade, e l'applicazione non può essere configurata a tale scopo, potrebbe non essere possibile risolvere il problema di bloccaggio. Per evitare il problema, è possibile limitare le applicazioni con comportamenti non ottimali a un database di reporting o di supporto decisionale, separato dal database OLTP principale.
L'impatto di questo scenario è ridotto quando lo snapshot Read Committed è abilitato nel database, ovvero la configurazione predefinita in Database SQL di Azure. Per altre informazioni, vedere la sezione Informazioni sul bloccaggio di questo articolo.
Nota
Vedere le indicazioni per la logica di ripetizione dei tentativi per le applicazioni che si connettono a database SQL di Azure.
Soluzione: l'applicazione deve essere riscritta per recuperare tutte le righe del risultato fino al completamento. Ciò non esclude l'uso di OFFSET e FETCH nella clausola ORDER BY di una query per eseguire il paging sul lato server.
Bloccaggio causato da una sessione nello stato di rollback
Viene eseguito il rollback di una query di modifica dei dati terminata o annullata, all'esterno di una transazione definita dall'utente. Ciò può verificarsi anche come effetto collaterale della disconnessione della sessione di rete client o quando una richiesta viene selezionata come vittima del deadlock. Questa operazione può essere spesso identificata osservando l'output di
sys.dm_exec_requests
, che può indicare il comando ROLLBACK e la colonnapercent_complete
può mostrare lo stato di avanzamento.Grazie a ripristino accelerato del database introdotto nel 2019, i rollback lunghi dovrebbero essere rari.
Soluzione: attendere il completamento del rollback delle modifiche apportate dallo SPID.
Per evitare questa situazione, non eseguire operazioni di scrittura batch di grandi dimensioni o operazioni di creazione o manutenzione degli indici durante le ore di lavoro nei sistemi OLTP. Se possibile, eseguire tali operazioni durante i periodi di bassa attività.
Bloccaggio causato da una connessione orfana
Se l'applicazione client intercetta degli errori oppure se la workstation client viene riavviata, la sessione di rete al server potrebbe non essere annullata immediatamente in alcune condizioni. Dal punto di vista del database SQL di Azure, il client sembra ancora presente e gli eventuali blocchi acquisiti potrebbero ancora essere trattenuti. Per ulteriori informazioni, vedere Come risolvere i problemi di connessioni orfane in SQL Server.
Risoluzione: se l'applicazione client si è disconnessa senza pulire correttamente le risorse, è possibile terminare la sessione usando il comando
KILL
. Il comandoKILL
accetta il valore dello SPID come input. Ad esempio, per terminare SPID 99, eseguire il comando seguente:KILL 99
Contenuto correlato
- Analizzare e impedire i deadlock nel database SQL di Azure e nel database SQL di Fabric
- Monitoraggio e ottimizzazione delle prestazioni nel database SQL di Azure e nell'istanza gestita di SQL di Azure
- Monitorare le prestazioni usando query store
- Guida sul blocco delle transazioni e sul versionamento delle righe
- SET TRANSACTION ISOLATION LEVEL (Transact-SQL)
- Avvio rapido : Eventi estesi
- Database SQL di Azure: migliorare l'ottimizzazione delle prestazioni con l'ottimizzazione automatica
- Offrire prestazioni coerenti con Azure SQL
- Risolvere i problemi di connettività e altri errori
- gestione degli errori temporanei
- Configurare il grado massimo di parallelismo (MAXDOP) nel database SQL di Azure
- Diagnosticare e risolvere i problemi di utilizzo elevato della CPU nel database SQL di Azure e nel database SQL in Microsoft Fabric