OlĂ¡ pessoal,
Bom dia!
Neste post, vou demonstrar como listar e eliminar processos que estĂ£o executando no servidor SQL Server utilizando o CLR (C#). Esses recursos podem ser especialmente Ăºteis para identificar rapidamente os processos de usuĂ¡rios que estĂ£o em execuĂ§Ă£o, quais processos estĂ£o utilizando mais memĂ³ria ou uso de CPU, por exemplo.
Durante o desenvolvimento de um script PowerShell, onde estava convertendo arquivos do Excel (XLSX) para PDF, os processos estavam “travando” aguardando alguma interaĂ§Ă£o na tela, que como eu estava executando via linha de comando lĂ¡ no servidor, nĂ£o tinha como terminar essa interaĂ§Ă£o. Diante disso, a cada teste, um novo processo ficava em execuĂ§Ă£o no servidor aguardando essa interaĂ§Ă£o.
Com isso, ficaram vĂ¡rios processos em execuĂ§Ă£o sem fazer nada. Por este motivo, optei por desenvolver uma Stored Procedure no CLR para eliminar esses processos do servidor. Caso vocĂª queira saber mais detalhes sobre o uso da biblioteca Process, veja mais acessando o meu post SQL Server – Como executar scripts PowerShell e Prompt-DOS (MS-DOS) utilizando CLR (C#).
Como listar processos no SQL Server utilizando a lib Process
Na Stored Procedure abaixo, eu utilizo a biblioteca Process e o mĂ©todo GetProcesses para retornar as informações dos processos em execuĂ§Ă£o no servidor em questĂ£o.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 |
using System; using System.Data; using System.Data.SqlTypes; using System.Diagnostics; using System.Linq; using Microsoft.SqlServer.Server; using Bibliotecas.Model; public partial class StoredProcedures { [Microsoft.SqlServer.Server.SqlProcedure] public static void stpProcessos_Listar(SqlString Ds_Servidor) { try { var pipe = SqlContext.Pipe; var colunas = new SqlMetaData[13]; colunas[0] = new SqlMetaData("PID", SqlDbType.Int); colunas[1] = new SqlMetaData("Ds_Processo", SqlDbType.NVarChar, 1024); colunas[2] = new SqlMetaData("Qt_Prioridade", SqlDbType.Int); colunas[3] = new SqlMetaData("Qt_Threads", SqlDbType.Int); colunas[4] = new SqlMetaData("Qt_Memoria_Fisica", SqlDbType.Float); colunas[5] = new SqlMetaData("Qt_Memoria_Fisica_Max", SqlDbType.Float); colunas[6] = new SqlMetaData("Qt_Memoria_Paginada", SqlDbType.Float); colunas[7] = new SqlMetaData("Qt_Memoria_Paginada_Max", SqlDbType.Float); colunas[8] = new SqlMetaData("Qt_Memoria_Privada", SqlDbType.Float); colunas[9] = new SqlMetaData("Qt_Memoria_Sistema_Paginada", SqlDbType.Float); colunas[10] = new SqlMetaData("Qt_Memoria_Sistema_Nao_Paginada", SqlDbType.Float); colunas[11] = new SqlMetaData("Qt_Memoria_Virtual", SqlDbType.Float); colunas[12] = new SqlMetaData("Qt_Memoria_Virtual_Max", SqlDbType.Float); var linhaSQL = new SqlDataRecord(colunas); pipe.SendResultsStart(linhaSQL); var processes = Process.GetProcesses(Ds_Servidor.Value); foreach (var process in processes.Where(process => !string.IsNullOrEmpty(process.ProcessName))) { linhaSQL.SetSqlInt32(0, new SqlInt32(process.Id)); linhaSQL.SetSqlString(1, new SqlString(process.ProcessName)); linhaSQL.SetSqlInt32(2, new SqlInt32(process.BasePriority)); linhaSQL.SetSqlInt32(3, new SqlInt32(process.Threads.Count)); linhaSQL.SetSqlDouble(4, new SqlDouble(process.WorkingSet64 / 1048576)); linhaSQL.SetSqlDouble(5, new SqlDouble(process.PeakWorkingSet64 / 1048576)); linhaSQL.SetSqlDouble(6, new SqlDouble(process.PagedMemorySize64 / 1048576)); linhaSQL.SetSqlDouble(7, new SqlDouble(process.PeakPagedMemorySize64 / 1048576)); linhaSQL.SetSqlDouble(8, new SqlDouble(process.PrivateMemorySize64 / 1048576)); linhaSQL.SetSqlDouble(9, new SqlDouble(process.PagedSystemMemorySize64 / 1048576)); linhaSQL.SetSqlDouble(10, new SqlDouble(process.NonpagedSystemMemorySize64 / 1048576)); linhaSQL.SetSqlDouble(11, new SqlDouble(process.VirtualMemorySize64 / 1048576)); linhaSQL.SetSqlDouble(12, new SqlDouble(process.PeakVirtualMemorySize64 / 1048576)); pipe.SendResultsRow(linhaSQL); } pipe.SendResultsEnd(); } catch (Exception e) { Retorno.Erro("Erro : " + e.Message); } } } |
Como listar processos no SQL Server utilizando o binĂ¡rio tasklist
Desta vez, vou utilizar novamente a biblioteca Process para executar o binĂ¡rio tasklist, que Ă© nativo do Windows, e exportar as informações retornadas pelo prompt do MS-DOS para CSV e tratar os dados no C#.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 |
using System; using System.Collections; using System.Data.SqlTypes; using System.Diagnostics; using System.Text; public partial class UserDefinedFunctions { private class ProcessProperties { public SqlString PID; public SqlString Ds_Processo; public SqlDouble Qt_Memoria; public SqlString Ds_Status; public SqlString Ds_Usuario; public SqlString Ds_Tempo_CPU; public ProcessProperties(SqlString pid, SqlString processo, SqlDouble memoria, SqlString status, SqlString usuario, SqlString cpu) { PID = pid; Ds_Processo = processo; Qt_Memoria = memoria; Ds_Status = status; Ds_Usuario = usuario; Ds_Tempo_CPU = cpu; } } [Microsoft.SqlServer.Server.SqlFunction( FillRowMethodName = "ListarProcessos", TableDefinition = "PID nvarchar(30), Ds_Processo nvarchar(1024), Qt_Memoria float, Ds_Status nvarchar(30), Ds_Usuario nvarchar(256), Ds_Tempo_CPU nvarchar(40)" )] public static IEnumerable fncProcessos_Listar(string Ds_Servidor) { var scriptProc = new Process { StartInfo = { FileName = @"tasklist", // Arquivo ou comando que serĂ¡ executado Arguments = "/S \"" + Ds_Servidor + "\" /V /FO csv", // ParĂ¢metros utilizados UseShellExecute = false, // Indica se deve usar o shell do sistema operacional para iniciar o processo RedirectStandardOutput = true, // Alertas e avisos serĂ£o exportados e disponĂveis para consulta RedirectStandardError = true, // Erros serĂ£o exportados e disponĂveis para consulta StandardOutputEncoding = Encoding.GetEncoding(850), // CodificaĂ§Ă£o Windows-1252 CreateNoWindow = true // O processo serĂ¡ executado sem criar uma nova janela } }; scriptProc.Start(); var output = scriptProc.StandardOutput.ReadToEnd(); var linhas = output.Split('\n'); var Qt_Linhas = (linhas.Length - 1); var ProcessPropertiesCollection = new ArrayList(); for (var i = 1; i < Qt_Linhas; i++) { var linha = linhas[i]; if (linha.Trim().Length <= 0) continue; var registro = linha.Replace("\",\"", "|").Replace("\"", "").Split('|'); if (registro.Length <= 4) continue; if (registro.Length > 7) { ProcessPropertiesCollection.Add(new ProcessProperties( registro[1], registro[0], Math.Round(double.Parse(registro[4].Replace(".", "").Replace(" K", "")) / 1024, 2), registro[5], registro[6], registro[7] )); } else { ProcessPropertiesCollection.Add(new ProcessProperties( registro[1], registro[0], Math.Round(double.Parse(registro[4].Replace(".", "").Replace(" K", "")) / 1024, 2), "", registro[5], registro[6] )); } } return ProcessPropertiesCollection; } protected static void ListarProcessos(object objProcessProperties, out SqlString pid, out SqlString processo, out SqlDouble memoria, out SqlString status, out SqlString usuario, out SqlString cpu) { var ProcessProperties = (ProcessProperties)objProcessProperties; pid = ProcessProperties.PID; processo = ProcessProperties.Ds_Processo; memoria = ProcessProperties.Qt_Memoria; status = ProcessProperties.Ds_Status; usuario = ProcessProperties.Ds_Usuario; cpu = ProcessProperties.Ds_Tempo_CPU; } } |
Como eliminar processos no SQL Server utilizando a lib Process
Para eliminar um processo do servidor onde estou atualmente conectado, podemos utilizar a biblioteca Process e o mĂ©todo Kill(), informando o nĂºmero do processo para que ele seja finalizado no servidor onde a Stored Procedure estĂ¡ sendo executada.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
using System; using System.Data.SqlTypes; using System.Diagnostics; using Bibliotecas.Model; public partial class StoredProcedures { [Microsoft.SqlServer.Server.SqlProcedure] public static void stpProcessos_Eliminar(SqlInt32 Nr_PID) { if (Nr_PID.IsNull) return; try { Process.GetProcessById(Nr_PID.Value).Kill(); } catch (Exception e) { Retorno.Erro("Erro : " + e.Message); } } } |
Como eliminar processos remotamente no SQL Server utilizando o binĂ¡rio taskkill
Diferente da Stored Procedure acima, neste exemplo vou utilizar a biblioteca Process para executar o binĂ¡rio nativo do Windows, taskkill.exe, para eliminar um processo atravĂ©s do PID informado, remotamente, ou seja, em qualquer servidor.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
using System; using System.Data.SqlTypes; using System.Diagnostics; using Bibliotecas.Model; public partial class StoredProcedures { [Microsoft.SqlServer.Server.SqlProcedure] public static void stpProcessos_Eliminar_Remoto(SqlString Ds_Servidor, SqlInt32 Nr_PID) { if (Ds_Servidor.IsNull || Nr_PID.IsNull) return; try { using (var scriptProc = new Process { StartInfo = { FileName = "taskkill.exe", // Arquivo ou comando que serĂ¡ executado Arguments = "/S " + Ds_Servidor.Value + " /F /PID " + Nr_PID.Value, UseShellExecute = false, // Indica se deve usar o shell do sistema operacional para iniciar o processo CreateNoWindow = true // O processo serĂ¡ executado sem criar uma nova janela } }) { scriptProc.Start(); scriptProc.WaitForExit(1000 * 5); // 5 segundos } } catch (Exception e) { Retorno.Erro("Erro : " + e.Message); } } } |
Como vocĂªs podem observar, em algumas Stored Procedures eu utilizo a classe Retorno para a exibiĂ§Ă£o de mensagens de alerta e mensagens de erro no banco de dados pelo CLR. O cĂ³digo-fonte dessa classe estĂ¡ disponĂvel no meu post SQL Server – Como enviar avisos e mensagens de erro para o banco pelo CLR (C#).
Espero que tenham gostado do post e até logo!
sql server clr c# csharp windows processo process list view listar visualizar relatĂ³rio kill eliminar matar processo
sql server clr c# csharp windows processo process list view listar visualizar relatĂ³rio kill eliminar matar processo