BlockingTreePrintService.cs 5.2 KB

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