BlockingTreePrintService.cs 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. using Dapper;
  2. using EVCB_OCPP.Domain;
  3. using EVCB_OCPP.Domain.ConnectionFactory;
  4. using EVCB_OCPP.WSServer.Helper;
  5. using Microsoft.Data.SqlClient;
  6. using Microsoft.Extensions.Logging;
  7. using System;
  8. using System.Collections.Generic;
  9. using System.ComponentModel.DataAnnotations.Schema;
  10. using System.Linq;
  11. using System.Text;
  12. using System.Threading.Tasks;
  13. namespace EVCB_OCPP.WSServer.Service
  14. {
  15. public class BlockingTreePrintService
  16. {
  17. public BlockingTreePrintService(ILogger<BlockingTreePrintService> logger,
  18. ISqlConnectionFactory<MainDBContext> connectionFactory)
  19. {
  20. this.logger = logger;
  21. this.connectionFactory = connectionFactory;
  22. }
  23. public async Task PrintDbBlockingTree()
  24. {
  25. using var connection = await connectionFactory.CreateAsync();
  26. var tree = await connection.QueryAsync<TreeStruct>(Command);
  27. logger.LogCritical("Printing BlockingTree");
  28. foreach (var data in tree)
  29. {
  30. logger.LogCritical($"{data.BlockingTree} {data.Type} {data.LoginName} {data.SourceDatabase} {data.SQLText} {data.CursorSQLText} {data.Database} {data.Schema} {data.Table} {data.WaitResource} {data.Command} {data.Application} {data.HostName} {data.LastBatchTime} ");
  31. }
  32. }
  33. private const string Command = """
  34. /* SQL Blocking Tree w/Cursor info
  35. Thanks SQL Server Expert JOHNNYBNO
  36. */
  37. IF OBJECT_ID('tempdb..#Blocks') IS NOT NULL
  38. DROP TABLE #Blocks
  39. SELECT spid
  40. ,blocked
  41. ,REPLACE (REPLACE (st.TEXT, CHAR(10), ' '), CHAR (13), ' ' ) AS batch
  42. INTO #Blocks
  43. FROM sys.sysprocesses spr
  44. CROSS APPLY sys.dm_exec_sql_text(spr.SQL_HANDLE) st;
  45. WITH BlockingTree (spid, blocking_spid, [level], batch)
  46. AS
  47. (
  48. SELECT blc.spid
  49. ,blc.blocked
  50. ,CAST (REPLICATE ('0', 4-LEN (CAST (blc.spid AS VARCHAR))) + CAST (blc.spid AS VARCHAR) AS VARCHAR (1000)) AS [level]
  51. ,blc.batch
  52. FROM #Blocks blc
  53. WHERE (blc.blocked = 0 OR blc.blocked = SPID) AND
  54. EXISTS (SELECT * FROM #Blocks blc2 WHERE blc2.BLOCKED = blc.SPID AND blc2.BLOCKED <> blc2.SPID)
  55. UNION ALL
  56. SELECT blc.spid
  57. ,blc.blocked
  58. ,CAST(bt.[level] + RIGHT (CAST ((1000 + blc.SPID) AS VARCHAR (100)), 4) AS VARCHAR (1000)) AS [level]
  59. ,blc.batch
  60. FROM #Blocks AS blc
  61. INNER JOIN BlockingTree bt
  62. ON blc.blocked = bt.SPID
  63. WHERE blc.blocked > 0 AND
  64. blc.blocked <> blc.SPID
  65. )
  66. SELECT N'' + ISNULL(REPLICATE (N'| ', LEN (LEVEL)/4 - 2),'')
  67. + CASE WHEN (LEN(LEVEL)/4 - 1) = 0 THEN '' ELSE '|------ ' END
  68. + CAST (bt.SPID AS NVARCHAR (10)) AS BlockingTree
  69. ,spr.lastwaittype AS [Type]
  70. ,spr.loginame AS [LoginName]
  71. ,DB_NAME(spr.dbid) AS [SourceDatabase]
  72. ,st.text AS [SQLText]
  73. ,CASE WHEN cur.sql_handle IS NULL THEN '' ELSE (SELECT [TEXT] FROM sys.dm_exec_sql_text (cur.sql_handle)) END AS [CursorSQLText]
  74. ,DB_NAME(sli.rsc_dbid) AS [Database]
  75. ,OBJECT_SCHEMA_NAME(sli.rsc_objid,sli.rsc_dbid) AS [Schema]
  76. ,OBJECT_NAME(sli.rsc_objid, sli.rsc_dbid) AS [Table]
  77. ,spr.waitresource AS [WaitResource]
  78. ,spr.cmd AS [Command]
  79. ,spr.program_name AS [Application]
  80. ,spr.hostname AS [HostName]
  81. ,spr.last_batch AS [Last Batch Time]
  82. FROM BlockingTree bt
  83. LEFT OUTER JOIN sys.sysprocesses spr
  84. ON spr.spid = bt.spid
  85. CROSS APPLY sys.dm_exec_sql_text(spr.SQL_HANDLE) st
  86. LEFT JOIN sys.dm_exec_cursors(0) cur
  87. ON cur.session_id = spr.spid AND
  88. cur.fetch_status != 0
  89. JOIN sys.syslockinfo sli
  90. ON sli.req_spid = spr.spid AND
  91. sli.rsc_type = 5 AND
  92. OBJECT_NAME(sli.rsc_objid, sli.rsc_dbid) IS NOT NULL
  93. ORDER BY LEVEL ASC
  94. """;
  95. private readonly ILogger<BlockingTreePrintService> logger;
  96. private readonly ISqlConnectionFactory<MainDBContext> connectionFactory;
  97. }
  98. public class TreeStruct
  99. {
  100. public string BlockingTree { get; set; }
  101. public string Type { get; set; }
  102. public string LoginName { get; set; }
  103. public string SourceDatabase { get; set; }
  104. public string SQLText { get; set; }
  105. public string CursorSQLText { get; set; }
  106. public string Database { get; set; }
  107. public string Schema { get; set; }
  108. public string Table { get; set; }
  109. public string WaitResource { get; set; }
  110. public string Command { get; set; }
  111. public string Application { get; set; }
  112. public string HostName { get; set; }
  113. public string LastBatchTime { get; set; }
  114. }
  115. }