Encontrar sesiones inactivas con transacción abierta

Una sesión aparece como sleeping, pero continúa bloqueando otras solicitudes o impide reutilizar espacio del log. No está ejecutando una petición y, aun así, conserva una transacción.

Qué necesitamos distinguir

sleeping indica que la sesión está conectada pero no ejecuta una solicitud. Una transacción abierta aún puede conservar bloqueos e impedir que el log reutilice registros necesarios para recuperar sus cambios.

Buscaremos sesiones de usuario inactivas asociadas con transacciones abiertas. También mostraremos cuándo terminó su última solicitud y el texto más reciente disponible, sin asumir que ese texto inició la transacción.

Consulta

/*
    Antes de ejecutar:
        Revisa los permisos y los límites antes de ejecutar la consulta.
        Confirma el alcance, la base activa y el costo posible de la consulta.
        Captura evidencia en varios momentos antes de atribuir una causa.

    Este script es de observación. No aplica correcciones ni modifica datos.
*/

SET NOCOUNT ON;
GO
-- Consulta
DECLARE @MinutosInactiva INT = 5;

SELECT
    s.session_id AS IdSesion,
    s.login_name AS InicioSesion,
    s.host_name AS EquipoCliente,
    s.program_name AS Aplicacion,
    s.status AS EstadoSesion,
    s.last_request_end_time AS FinUltimaSolicitud,
    DATEDIFF_BIG
    (
        SECOND,
        s.last_request_end_time,
        SYSDATETIME()
    ) AS SegundosInactiva,
    ta.transaction_id AS IdTransaccion,
    ta.transaction_begin_time AS InicioTransaccion,
    DATEDIFF_BIG
    (
        SECOND,
        ta.transaction_begin_time,
        SYSDATETIME()
    ) AS SegundosTransaccionAbierta,
    st.open_transaction_count AS TransaccionesAbiertas,
    st.is_local AS EsLocal,
    st.is_enlisted AS EstaEnlistada,
    texto.text AS TextoMasReciente
FROM sys.dm_exec_sessions AS s
INNER JOIN sys.dm_tran_session_transactions AS st
    ON st.session_id = s.session_id
INNER JOIN sys.dm_tran_active_transactions AS ta
    ON ta.transaction_id = st.transaction_id
OUTER APPLY
(
    SELECT TOP (1)
        c.most_recent_sql_handle,
        c.connect_time
    FROM sys.dm_exec_connections AS c
    WHERE c.session_id = s.session_id
    ORDER BY c.connect_time DESC
) AS conexion
OUTER APPLY sys.dm_exec_sql_text
(
    conexion.most_recent_sql_handle
) AS texto
WHERE s.is_user_process = 1
  AND s.status = N'sleeping'
  AND st.is_user_transaction = 1
  AND s.last_request_end_time <=
      DATEADD(MINUTE, -@MinutosInactiva, SYSDATETIME())
ORDER BY
    ta.transaction_begin_time,
    s.session_id;
GO

Parámetros o permisos

@MinutosInactiva evita mostrar conexiones que apenas terminaron una solicitud. Ajusta el umbral a la duración normal entre operaciones de la aplicación. Se necesita visibilidad sobre sesiones, conexiones y transacciones del servidor. El conteo de transacciones de sys.dm_tran_session_transactions puede no coincidir con el de sys.dm_exec_sessions en escenarios como transacciones enlazadas o distribuidas; aquí se conserva el valor de la asociación consultada.

Cómo leer el resultado

sleeping significa que la sesión no ejecuta una solicitud en ese instante, no que haya liberado su transacción. Compara FinUltimaSolicitud con InicioTransaccion: una inactividad prolongada después de abrir la transacción merece revisar el manejo de conexión y de COMMIT o ROLLBACK en la aplicación. TextoMasReciente es la última instrucción conocida para la conexión. Puede haber ejecutado varias sentencias desde que comenzó la transacción, por lo que debe tratarse como una pista.

Qué conclusión sí permite obtener

Permite identificar sesiones de usuario inactivas que siguen asociadas con una transacción y medir cuánto tiempo llevan en ese estado observable.

Qué conclusión todavía no permite obtener

No demuestra cuál instrucción dejó abierta la transacción, cuánto tardaría una reversión ni si la conexión pertenece a un proceso que espera legítimamente otra operación.

Siguiente comprobación razonable

Relaciona la sesión con las sesiones bloqueadoras y bloqueadas y con la cadena completa de bloqueo. Después revisa el flujo de la aplicación: apertura de conexión, inicio de transacción, manejo de excepciones y caminos que omiten COMMIT, ROLLBACK o liberación del recurso.

Índice del recorrido

Diagnóstico y optimización

23 artículos de Diagnóstico y optimización
  1. 01Ver solicitudes activas y su consulta SQL
  2. 02Identificar sesiones bloqueadoras y bloqueadas
  3. 03Construir la cadena de bloqueo
  4. 04Encontrar transacciones abiertas por mucho tiempo
  5. 05Encontrar sesiones inactivas con transacción abierta
  6. 06Ver esperas de las solicitudes activas
  7. 07Revisar las principales esperas acumuladas
  8. 08Encontrar consultas con mayor consumo total de CPU
  9. 09Encontrar consultas con mayor lectura lógica
  10. 10Encontrar consultas con mayor duración promedio
  11. 11Recuperar el plan de ejecución almacenado
  12. 12Revisar sugerencias de índices faltantes
  13. 13Revisar uso de índices
  14. 14Revisar fragmentación de índices con alcance controlado
  15. 15Revisar antigüedad y modificación de estadísticas
  16. 16Medir el uso de espacio y log de cada base
  17. 17Diagnosticar por qué el log no puede reutilizarse
  18. 18Recuperar deadlocks recientes de system_health
  19. 19Encontrar consultas degradadas mediante Query Store
  20. 20Encontrar sesiones y solicitudes que consumen tempdb
  21. 21Revisar concesiones de memoria pendientes o excesivas
  22. 22Calcular latencia de lectura y escritura por archivo
  23. 23Encontrar consultas con varios planes y rendimientos diferentes