Solución de problemas de consultas que parecen nunca terminar en SQL Server
En este artículo se describen los pasos para solucionar el problema en el que tiene una consulta que parece no completarse nunca, o para que se complete puede tardar muchas horas o días.
¿Qué es una consulta interminable?
Este documento se centra en las consultas que continúan ejecutándose o compilando, es decir, su CPU sigue aumentando. No se aplica a las consultas que están bloqueadas o esperando en algún recurso que nunca se libera (la CPU sigue siendo constante o cambia muy poco).
Importante
Si se deja una consulta para finalizar su ejecución, finalmente se completará. Puede tardar unos segundos, o puede tardar varios días.
El término never-ending se usa para describir la percepción de que una consulta no se completa cuando, de hecho, la consulta se completará finalmente.
Identificación de una consulta sin fin
Para identificar si una consulta se ejecuta continuamente o se bloquea en un cuello de botella, siga estos pasos:
Ejecute la consulta siguiente:
DECLARE @cntr int = 0 WHILE (@cntr < 3) BEGIN SELECT TOP 10 s.session_id, r.status, r.wait_time, r.wait_type, r.wait_resource, r.cpu_time, r.logical_reads, r.reads, r.writes, r.total_elapsed_time / (1000 * 60) 'Elaps M', SUBSTRING(st.TEXT, (r.statement_start_offset / 2) + 1, ((CASE r.statement_end_offset WHEN -1 THEN DATALENGTH(st.TEXT) ELSE r.statement_end_offset END - r.statement_start_offset) / 2) + 1) AS statement_text, COALESCE(QUOTENAME(DB_NAME(st.dbid)) + N'.' + QUOTENAME(OBJECT_SCHEMA_NAME(st.objectid, st.dbid)) + N'.' + QUOTENAME(OBJECT_NAME(st.objectid, st.dbid)), '') AS command_text, r.command, s.login_name, s.host_name, s.program_name, s.last_request_end_time, s.login_time, r.open_transaction_count, atrn.name as transaction_name, atrn.transaction_id, atrn.transaction_state FROM sys.dm_exec_sessions AS s JOIN sys.dm_exec_requests AS r ON r.session_id = s.session_id CROSS APPLY sys.Dm_exec_sql_text(r.sql_handle) AS st LEFT JOIN (sys.dm_tran_session_transactions AS stran JOIN sys.dm_tran_active_transactions AS atrn ON stran.transaction_id = atrn.transaction_id) ON stran.session_id =s.session_id WHERE r.session_id != @@SPID ORDER BY r.cpu_time DESC SET @cntr = @cntr + 1 WAITFOR DELAY '00:00:05' END
Compruebe la salida de ejemplo.
Los pasos de solución de problemas de este artículo se aplican específicamente cuando se observa una salida similar a la siguiente en la que la CPU aumenta proporcionalmente con el tiempo transcurrido, sin tiempos de espera significativos. Es importante tener en cuenta que los cambios en
logical_reads
no son pertinentes en este caso, ya que es posible que algunas solicitudes T-SQL enlazadas a la CPU no realicen ninguna lectura lógica (por ejemplo, realizar cálculos o unWHILE
bucle).session_id status cpu_time logical_reads wait_time wait_type 56 Corriendo 7038 101000 0 NULL 56 ejecutable 12040 301000 0 NULL 56 Corriendo 17020 523000 0 NULL Este artículo no es aplicable si observa un escenario de espera similar al siguiente en el que la CPU no cambia o cambia muy ligeramente y la sesión está esperando en un recurso.
session_id status cpu_time logical_reads wait_time wait_type 56 suspended 0 3 8312 LCK_M_U 56 suspended 0 3 13318 LCK_M_U 56 suspended 0 5 18331 LCK_M_U
Para obtener más información, consulte Diagnóstico de esperas o cuellos de botella.
Tiempo de compilación largo
En raras ocasiones, es posible que observe que la CPU aumenta continuamente con el tiempo, pero eso no está controlado por la ejecución de consultas. En su lugar, podría estar controlada por una compilación excesivamente larga (análisis y compilación de una consulta). En esos casos, compruebe la columna de salida transaction_name y busque un valor de sqlsource_transform
. Este nombre de transacción indica una compilación.
Recopilación de datos de diagnóstico
- SQL Server 2008- SQL Server 2014 (antes de SP2)
- SQL Server 2014 (después de SP2) y SQL Server 2016 (antes de SP1)
- SQL Server 2016 (después de SP1) y SQL Server 2017
- SQL Server 2019 y versiones posteriores
Para recopilar datos de diagnóstico mediante SQL Server Management Studio (SSMS), siga estos pasos:
Capture el XML del plan de ejecución de consultas estimado .
Revise el plan de consulta para ver si hay alguna indicación obvia de de dónde puede provenir la lentitud. Entre los ejemplos típicos se incluyen:
- Exámenes de tabla o índice (examine las filas estimadas).
- Bucles anidados controlados por un enorme conjunto de datos de tabla externa.
- Bucles anidados con una rama grande en el lado interno del bucle.
- Grupos de tablas.
- Funciones de la
SELECT
lista que tardan mucho tiempo en procesar cada fila.
Si la consulta se ejecuta rápidamente en cualquier momento, puede capturar las ejecuciones "rápidas" del plan de ejecución XML real que se va a comparar.
Método para revisar los planes recopilados
En esta sección se muestra cómo revisar los datos recopilados. Usará los varios planes de consulta XML (mediante la extensión *.sqlplan) recopilados en SQL Server 2016 SP1 y versiones posteriores.
Siga estos pasos para comparar los planes de ejecución:
Abra un archivo de plan de ejecución de consultas guardado anteriormente (.sqlplan).
Haga clic con el botón derecho en un área en blanco del plan de ejecución y seleccione Comparar plan de presentación.
Elija el segundo archivo de plan de consulta que desea comparar.
Busque flechas gruesas que indiquen un gran número de filas que fluyen entre operadores. A continuación, seleccione el operador antes o después de la flecha y compare el número de filas reales en dos planes.
Compare los planes segundo y tercero para ver si el flujo más grande de filas se produce en los mismos operadores.
Aquí le mostramos un ejemplo:
Solución
Asegúrese de que las estadísticas se actualizan para las tablas usadas en la consulta.
Busque una recomendación de índice que falte en el plan de consulta y aplique cualquiera.
Vuelva a escribir la consulta con el objetivo de simplificarla:
- Use predicados más selectivos
WHERE
para reducir los datos procesados por adelantado. - Desmoronarse.
- Seleccione algunas partes en tablas temporales y únase a ellas más adelante.
- Quite
TOP
,EXISTS
yFAST
(T-SQL) en las consultas que se ejecutan durante mucho tiempo debido al objetivo de fila del optimizador. Como alternativa, puede usar laDISABLE_OPTIMIZER_ROWGOAL
sugerencia. Para obtener más información, vea Row Goals Gone Rogue. - Evite usar expresiones de tabla comunes (CTE) en casos como cuando combinen instrucciones en una sola consulta grande.
- Use predicados más selectivos
Pruebe a usar sugerencias de consulta para generar un mejor plan:
HASH JOIN
oMERGE JOIN
sugerenciaFORCE ORDER
PistaFORCESEEK
PistaRECOMPILE
- USE
PLAN N'<xml_plan>'
si tiene un plan de consulta rápido que puede forzar
Use Almacén de consultas (QDS) para forzar un plan conocido si existe este tipo de plan y si la versión de SQL Server admite Almacén de consultas.
Diagnóstico de esperas o cuellos de botella
Esta sección se incluye aquí como referencia en caso de que el problema no sea una consulta de conducción de CPU de larga duración. Puede usarlo para solucionar problemas de consultas que son largas debido a esperas.
Para optimizar una consulta que espera cuellos de botella, identifique cuánto tiempo es la espera y dónde está el cuello de botella (el tipo de espera). Una vez confirmado el tipo de espera , reduzca el tiempo de espera o elimine la espera por completo.
Para calcular el tiempo de espera aproximado, reste el tiempo de CPU (tiempo de trabajo) del tiempo transcurrido de una consulta. Normalmente, el tiempo de CPU es el tiempo de ejecución real y la parte restante de la duración de la consulta está esperando.
Ejemplos de cómo calcular la duración aproximada de la espera:
Tiempo transcurrido (ms) | Tiempo de CPU (ms) | Tiempo de espera (ms) |
---|---|---|
3200 | 3000 | 200 |
7080 | 1000 | 6080 |
Identificar el cuello de botella o la espera
Para identificar consultas históricas de larga espera (por ejemplo, >el 20 % del tiempo total transcurrido es tiempo de espera), ejecute la consulta siguiente. Esta consulta usa estadísticas de rendimiento para los planes de consulta almacenados en caché desde el inicio de SQL Server.
SELECT t.text, qs.total_elapsed_time / qs.execution_count AS avg_elapsed_time, qs.total_worker_time / qs.execution_count AS avg_cpu_time, (qs.total_elapsed_time - qs.total_worker_time) / qs.execution_count AS avg_wait_time, qs.total_logical_reads / qs.execution_count AS avg_logical_reads, qs.total_logical_writes / qs.execution_count AS avg_writes, qs.total_elapsed_time AS cumulative_elapsed_time FROM sys.dm_exec_query_stats qs CROSS apply sys.Dm_exec_sql_text (sql_handle) t WHERE (qs.total_elapsed_time - qs.total_worker_time) / qs.total_elapsed_time > 0.2 ORDER BY qs.total_elapsed_time / qs.execution_count DESC
Para identificar las consultas que se ejecutan actualmente con esperas superiores a 500 ms, ejecute la consulta siguiente:
SELECT r.session_id, r.wait_type, r.wait_time AS wait_time_ms FROM sys.dm_exec_requests r JOIN sys.dm_exec_sessions s ON r.session_id = s.session_id WHERE wait_time > 500 AND is_user_process = 1
Si puede recopilar un plan de consulta, compruebe waitstats de las propiedades del plan de ejecución en SSMS:
- Ejecute la consulta con Incluir plan de ejecución real activado.
- Haga clic con el botón derecho en el operador de la izquierda en la pestaña Plan de ejecución.
- Seleccione Propiedades y, a continuación, la propiedad WaitStats .
- Compruebe WaitTimeMs y WaitType.
Si está familiarizado con los escenarios PSSDiag/SQLdiag o SQL LogScout LightPerf/GeneralPerf, considere la posibilidad de usar cualquiera de ellos para recopilar estadísticas de rendimiento e identificar consultas en espera en la instancia de SQL Server. Puede importar los archivos de datos recopilados y analizar los datos de rendimiento con SQL Nexus.
Referencias para ayudar a eliminar o reducir las esperas
Las causas y las resoluciones de cada tipo de espera varían. No hay ningún método general para resolver todos los tipos de espera. Estos son los artículos para solucionar problemas comunes de tipo de espera:
- Descripción y resolución de problemas de bloqueo (LCK_M_*)
- Descripción y resolución de problemas de bloqueo de Azure SQL Base de datos
- Solución de problemas de rendimiento lento SQL Server causados por problemas de E/S (PAGEIOLATCH_*, WRITELOG, IO_COMPLETION, BACKUPIO)
- Resolución de la contención de inserción de última página PAGELATCH_EX en SQL Server
- La memoria concede explicaciones y soluciones (RESOURCE_SEMAPHORE)
- Solución de problemas de consultas lentas resultantes de ASYNC_NETWORK_IO tipo de espera
- Solución de problemas de tipo de espera de alta HADR_SYNC_COMMIT con grupos de disponibilidad de Always On
- Cómo funciona: CMEMTHREAD y depurarlos
- Hacer que las esperas de paralelismo sean accionables (CXPACKET y CXCONSUMER)
- ESPERA DE THREADPOOL
Para obtener descripciones de muchos tipos de espera y lo que indican, vea la tabla en Tipos de esperas.
Comentarios
https://aka.ms/ContentUserFeedback.
Próximamente: A lo largo de 2024 iremos eliminando gradualmente GitHub Issues como mecanismo de comentarios sobre el contenido y lo sustituiremos por un nuevo sistema de comentarios. Para más información, vea:Enviar y ver comentarios de