Hola, chicos,
¡Buen día!
En esta publicación, demostraré cómo enumerar y eliminar procesos que se ejecutan en el servidor SQL Server usando CLR (C#). Estas características pueden ser especialmente útiles para identificar rápidamente qué procesos de usuario se están ejecutando, qué procesos están usando más memoria o uso de CPU, por ejemplo.
Durante el desarrollo de un script de PowerShell, donde estaba convirtiendo archivos Excel (XLSX) a PDF, los procesos se quedaban “colgados” esperando alguna interacción en la pantalla, la cual como estaba ejecutando a través de la línea de comandos en el servidor, no había forma de finalizar esta interacción. Por lo tanto, con cada prueba, se ejecutaba un nuevo proceso en el servidor esperando esta interacción.
Como resultado, varios procesos quedaron ejecutándose sin hacer nada. Por este motivo, opté por desarrollar un Procedimiento Almacenado en el CLR para eliminar estos procesos del servidor. Si quieres conocer más detalles sobre el uso de la biblioteca de Procesos, mira más accediendo a mi post SQL Server: cómo ejecutar scripts de PowerShell y Prompt-DOS (MS-DOS) usando CLR (C#).
Cómo enumerar procesos en SQL Server usando la biblioteca de procesos
En el procedimiento almacenado a continuación, utilizo la biblioteca Process y el método GetProcesses para devolver información sobre los procesos que se ejecutan en el servidor en cuestión.

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);
}
}
}
Cómo enumerar procesos en SQL Server usando el binario de lista de tareas
Esta vez, usaré nuevamente la biblioteca de procesos para ejecutar el binario de la lista de tareas, que es nativo de Windows, y exportaré la información devuelta por el indicador de MS-DOS a CSV y procesaré los datos en C#.

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;
}
}
Cómo eliminar procesos en SQL Server usando la biblioteca de procesos
Para matar un proceso en el servidor donde estoy conectado actualmente, podemos usar la biblioteca Process y el método Kill(), informando el número del proceso para que pueda terminarse en el servidor donde se está ejecutando el Procedimiento Almacenado.

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);
}
}
}
Cómo eliminar procesos de forma remota en SQL Server usando el binario taskkill
A diferencia del procedimiento almacenado anterior, en este ejemplo usaré la biblioteca de procesos para ejecutar el binario nativo de Windows, taskkill.exe, para finalizar un proceso usando el PID informado, de forma remota, es decir, en cualquier servidor.

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 puede ver, en algunos procedimientos almacenados utilizo la clase Return para mostrar mensajes de alerta y mensajes de error en la base de datos a través de CLR. El código fuente de esta clase está disponible en mi publicación. SQL Server: cómo enviar advertencias y mensajes de error a la base de datos usando CLR (C#).
Espero que os haya gustado el post y ¡hasta pronto!
servidor sql clr c# csharp proceso de windows vista de lista de procesos vista de lista informe matar matar matar proceso
servidor sql clr c# csharp proceso de windows vista de lista de procesos vista de lista informe matar matar matar proceso
Comentários (0)
Carregando comentários…