Voy a decir desde el principio que mi pregunta / problema es similar a esta anterior, pero ya no estoy seguro de si la causa o la información de partida es el mismo, decidí publicar mi pregunta con algunos detalles más.
Tema en cuestión:
- a una hora extraña (cerca del final del día laboral) una instancia de producción comienza a comportarse de manera errática:
- CPU alta para la instancia (desde una línea base de ~ 30% fue casi el doble y todavía estaba creciendo)
- mayor número de transacciones / segundo (aunque la carga de la aplicación no ha visto ningún cambio)
- mayor número de sesiones inactivas
- eventos de bloqueo extraños entre sesiones que nunca mostraron este comportamiento (incluso leer sesiones no confirmadas causaban bloqueo)
- las esperas superiores para el intervalo no fueron el cierre de la página en el primer lugar, con los bloqueos en el segundo lugar
Investigación inicial:
- usando sp_whoIsActive vimos que una consulta ejecutada por nuestra herramienta de monitoreo decide ejecutarse extremadamente lento y tomar mucha CPU, algo que no sucedió antes;
- su nivel de aislamiento fue leído no comprometido;
- miramos el plan, vimos números extravagantes: StatementEstRows = "3.86846e + 010" con unos 150 TB de datos estimados que se devolverán
- sospechamos que la función de monitoreo de consultas de la herramienta de monitoreo era la causa, por lo que deshabilitamos la función (también abrimos un ticket con nuestro proveedor para verificar si están al tanto de algún problema)
- desde ese primer evento, sucedió unas cuantas veces más, con cada vez que cerramos la sesión, todo vuelve a la normalidad;
- nos damos cuenta de que la consulta es extremadamente similar a una de las consultas utilizadas por MS en BOL para el monitoreo del Almacén de consultas: consultas que recientemente regresaron en rendimiento (comparando diferentes puntos en el tiempo)
- ejecutamos la misma consulta manualmente y vemos el mismo comportamiento (la CPU se usa cada vez más, aumentando las esperas de bloqueo, bloqueos inesperados, etc.)
Consulta culpable:
Select qt.query_sql_text,
q.query_id,
qt.query_text_id,
rs1.runtime_stats_id AS runtime_stats_id_1,
interval_1 = DateAdd(minute, -(DateDiff(minute, getdate(), getutcdate())), rsi1.start_time),
p1.plan_id AS plan_1,
rs1.avg_duration AS avg_duration_1,
rs2.avg_duration AS avg_duration_2,
p2.plan_id AS plan_2,
interval_2 = DateAdd(minute, -(DateDiff(minute, getdate(), getutcdate())), rsi2.start_time),
rs2.runtime_stats_id AS runtime_stats_id_2
From sys.query_store_query_text AS qt
Inner Join sys.query_store_query AS q
ON qt.query_text_id = q.query_text_id
Inner Join sys.query_store_plan AS p1
ON q.query_id = p1.query_id
Inner Join sys.query_store_runtime_stats AS rs1
ON p1.plan_id = rs1.plan_id
Inner Join sys.query_store_runtime_stats_interval AS rsi1
ON rsi1.runtime_stats_interval_id = rs1.runtime_stats_interval_id
Inner Join sys.query_store_plan AS p2
ON q.query_id = p2.query_id
Inner Join sys.query_store_runtime_stats AS rs2
ON p2.plan_id = rs2.plan_id
Inner Join sys.query_store_runtime_stats_interval AS rsi2
ON rsi2.runtime_stats_interval_id = rs2.runtime_stats_interval_id
Where rsi1.start_time > DATEADD(hour, -48, GETUTCDATE())
AND rsi2.start_time > rsi1.start_time
AND p1.plan_id <> p2.plan_id
AND rs2.avg_duration > rs1.avg_duration * 2
Order By q.query_id, rsi1.start_time, rsi2.start_time
Configuraciones e información:
- SQL Server 2016 SP1 CU4 Enterprise en un clúster de Windows Server 2012R2
- Query Store habilitado y configurado como predeterminado (no se modificó la configuración)
- base de datos importada de una instancia de SQL 2005 (y aún en el nivel de compatibilidad 100)
Observación empírica:
- Debido a las estadísticas extremadamente extravagantes, tomamos todos los objetos * plan_persist ** utilizados en el plan estimado incorrecto (todavía no hay un plan real, porque la consulta nunca terminó) y verificamos estadísticas, algunos de los índices utilizados en el plan no tenían ninguna estadística (DBCC SHOWSTATISTICS no devolvió nada, seleccione de sys.stats mostró la función NULL stats_date () para algunos índices
Solución rápida y sucia:
- crear manualmente estadísticas faltantes en objetos del sistema relacionados con el Almacén de consultas o
- forzar la ejecución de la consulta utilizando el nuevo CE (traceflag), que también creará / actualizará las estadísticas necesarias o
- cambie el nivel de compatibilidad de la base de datos a 130 (por lo que, de manera predeterminada, usará el nuevo CE)
Entonces, mi verdadera pregunta sería:
¿Por qué una consulta en Query Store causa problemas de rendimiento en toda la instancia? ¿Estamos en un territorio de errores con Query Store?
PD: Subiré algunos archivos (pantallas de impresión, estadísticas de IO y planes) en breve.
Archivos agregados en Dropbox .
Plan 1 - plan estimado inicial loco en producción
Plan 2 : plan real, CE anterior, en un entorno de prueba (mismo comportamiento, mismas estadísticas extravagantes)
Plan 3 - plan real, nueva CE, en un entorno de prueba