Estou trabalhando em um aplicativo multithread (VB.Net/C#), que está trabalhando em um banco de dados SQL-server.
Regularmente, meu cliente reclama que o aplicativo mostra exceções do tipo "impasse" sobre o chamado SQLClient e, ao reiniciar o aplicativo, tudo funciona bem novamente (por um tempo).
Pela descrição, não acredito que meu cliente esteja enfrentando um impasse real (um thread aguardando outro thread), mas acredito que estou lidando com duas solicitações de banco de dados, provavelmente na mesma tabela, onde uma transação leva tanto vez que bloqueia a outra transação, mas isso é apenas um palpite, e gostaria de ter certeza disso. Para isso, estou pensando em perguntar ao banco de dados quais threads estão acessando qual(is) tabela(s), espero que isso me dê algumas informações.
Pesquisando no site aqui, descobri a dm_db_index_operational_stats
tabela, mencionada nesta outra pergunta , mas sendo um novato, isso parece bastante complicado, portanto, gostaria de fazer isso como uma pergunta simples:
Como posso saber quais threads de qual aplicativo estão acessando quais tabelas no meu banco de dados SQL-server? Obviamente, quanto mais informações (ID do processo, ID do thread, nome do thread, (parte superior da) pilha de chamadas, ...) melhor.
Isso existe?
No que diz respeito a uma possível solução:
Meu aplicativo é baseado nesta DLL:
"C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.0\System.Data.dll"
... faz o seguinte para acessar o banco de dados (por exemplo, para remover entradas obsoletas):
Public Shared Sub ExecuteSQL(ByVal sSQL As String, ByVal ParamArray dbParams() As SqlParameter)
Dim oCommand As SqlCommand = Nothing
Try
oCommand = BuildCommand(sSQL, dbParams)
oCommand.CommandTimeout = 60
oCommand.ExecuteNonQuery()
Catch ex As Exception
Debug.WriteLine(ex.Message)
Throw
Finally
If oCommand IsNot Nothing Then ReleaseConnection(oCommand.Connection)
End Try
End Sub
Gostaria de adicionar um mecanismo de bloqueio para evitar este tipo de problemas, algo como:
DatabaseConnection.Lock_Table("Table_which_is_handled");
ExecuteSQL(...); // working on "Table_which_is_handled"
DatabaseConnection.Release_Lock_Table("Table_which_is_handled");
Isso existe?
Alguém tem uma ideia?
desde já, obrigado
Editar após discussão com Dan Huzman :
Esta resposta , referida por Dan Huzman , menciona a seguinte consulta SQL:
--Get xml_deadlock_report events from system_health session file target
WITH
--get trace folder path and append session name with wildcard (assumes base file name is same as session name)
all_trace_files AS (
SELECT path + '\system_health*.xel' AS FileNamePattern
FROM sys.dm_os_server_diagnostics_log_configurations
)
--get xml_deadlock_report events from all system_health trace files
, deadlock_reports AS (
SELECT CAST(event_data AS xml) AS deadlock_report_xml
FROM all_trace_files
CROSS APPLY sys.fn_xe_file_target_read_file ( FileNamePattern, NULL, NULL, NULL) AS trace_records
WHERE trace_records.object_name like 'xml_deadlock_report'
)
SELECT TOP 10
deadlock_report_xml.value('(/event/@timestamp)[1]', 'datetime2') AS UtcTimestamp
, deadlock_report_xml AS DeadlockReportXml
FROM deadlock_reports;
Isso se refere a alguns arquivos, localizados no computador do cliente, provavelmente no diretório "C:\Arquivos de Programas\Microsoft SQL Server\MSSQL15.SQLEXPRESS\MSSQL\Log" (para ter certeza, verifique ) SELECT path FROM sys.dm_os_server_diagnostics_log_configurations
.
Posso recuperar os arquivos "system_health*.xel" mencionados e colocá-los no meu computador local (digamos, no diretório "C:\Temp_Folder") e, em seguida, iniciar a seguinte nova consulta:
--Get xml_deadlock_report events from system_health session file target
WITH
--get trace folder path and append session name with wildcard (assumes base file name is same as session name)
all_trace_files AS (
SELECT 'C:\Temp_Folder\system_health*.xel' AS FileNamePattern
FROM sys.dm_os_server_diagnostics_log_configurations
)
--get xml_deadlock_report events from all system_health trace files
, deadlock_reports AS (
SELECT CAST(event_data AS xml) AS deadlock_report_xml
FROM all_trace_files
CROSS APPLY sys.fn_xe_file_target_read_file ( FileNamePattern, NULL, NULL, NULL) AS trace_records
WHERE trace_records.object_name like 'xml_deadlock_report'
)
SELECT deadlock_report_xml.value('(/event/@timestamp)[1]', 'datetime2') AS UtcTimestamp
, deadlock_report_xml AS DeadlockReportXml
FROM deadlock_reports;
Isso me daria as informações que estou procurando ou preciso abrir uma sessão do Microsoft SQL Server Management Studio no computador do meu cliente?
Um impasse não é apenas uma thread esperando pela outra (bloqueio), mas mais 2 threads esperando uma pela outra (conflito). Os impasses geralmente podem ser resolvidos com ajuste de consulta/índice, em vez de ir tão longe a ponto de serializar o acesso ao banco de dados.
O
xml_deadlock_report
é capturado pelosystem_health
rastreamento de evento estendido e ajudará a identificar os processos e recursos envolvidos em impasses recentes. As informações de impasse podem ser obtidas com as consultas coletadas dos comentários e adicionadas à sua pergunta.