Estadísticas desactualizadas y sniffing: cómo distinguir y corregir ambos problemas

Estadísticas desactualizadas y sniffing: cómo distinguir y corregir ambos problemas

0
(0)

En la consultoría de Business Intelligence, nos enfrentamos a menudo a la degradación repentina del rendimiento de un informe de Power BI que hasta ayer funcionaba perfectamente. El síntoma es clásico: una consulta que tardaba tres segundos ahora tarda tres minutos. Lo primero que suele hacer el desarrollador es culpar al modelo o a la red, pero si el origen es SQL Server, el problema suele esconderse en dos culpables que se mimetizan: las estadísticas desactualizadas y el parameter sniffing.

Confundirlos es un error costoso. Si aplicas una solución para el sniffing (como un OPTIMIZE FOR UNKNOWN) cuando el problema es que las estadísticas no reflejan la realidad de la tabla de Ventas, solo estarás poniendo un parche que fallará en la siguiente carga de datos. Por el contrario, reconstruir estadísticas para solucionar un problema de sniffing es perder el tiempo, ya que el plan de ejecución seguirá siendo óptimo para un valor que no es el que el usuario está filtrando en ese momento.

Como consultor, he visto proyectos de retail donde la tabla de Tickets crece millones de filas al día. En estos escenarios, el motor de SQL Server puede tomar decisiones basadas en una realidad de hace una semana. Para evitarlo, debemos saber medir antes de actuar, utilizando herramientas como los Server Timings o analizando directamente los metadatos del motor.

La raíz del problema: ¿Por qué el motor se equivoca?

SQL Server es un optimizador basado en costes. Antes de ejecutar una consulta, estima cuántas filas devolverá cada operador (Scan, Seek, Join). Para esta estimación, utiliza las estadísticas, que son esencialmente histogramas y vectores de densidad que describen la distribución de los datos en una columna o índice.

El problema surge cuando la estimación de cardinalidad falla. Si el optimizador cree que una consulta devolverá 10 filas pero en realidad devuelve 1.000.000, elegirá un plan de ejecución ineficiente, como un Nested Loop en lugar de un Hash Join. Esta discrepancia puede deberse a dos causas raíz distintas que debemos aprender a separar.

Estadísticas desactualizadas: El mapa no coincide con el terreno

Las estadísticas se actualizan automáticamente cuando se alcanza un umbral de modificaciones (filas insertadas, borradas o actualizadas). Sin embargo, en tablas muy grandes, este umbral puede tardar demasiado en alcanzarse. Si has cargado un histórico masivo en tu tabla de Hechos_Energia y no has forzado una actualización, el optimizador no sabrá que existen nuevos rangos de fechas o nuevas categorías de consumo.

Parameter Sniffing: El plan ‘heredado’

El parameter sniffing ocurre cuando SQL Server ‘olfatea’ el valor de los parámetros la primera vez que se ejecuta un procedimiento almacenado o una consulta parametrizada. Genera un plan óptimo para ese valor específico y lo guarda en la caché. Si el primer usuario filtra por un Id_Cliente que solo tiene dos compras, el plan será muy ligero. Si el segundo usuario filtra por un cliente mayorista con medio millón de compras, SQL Server intentará usar el mismo plan ligero, provocando un colapso por lecturas lógicas excesivas.

Cómo validar la antigüedad y salud de las estadísticas

No asumas que SQL Server ha actualizado las estadísticas por ti. En versiones antiguas (anteriores a SQL Server 2016 SP1 CU4), el umbral por defecto era del 20% + 500 filas, lo cual es inaceptable para tablas de millones de registros. Aunque en versiones modernas el umbral es dinámico, siempre debemos verificarlo.

Para auditar el estado de las estadísticas en nuestras tablas de negocio, utilizaremos la vista de administración dinámica sys.dm_db_stats_properties. Este script nos permite identificar qué estadísticas están obsoletas basándonos en el número de modificaciones desde la última actualización:

-- Consultar el estado de las estadísticas en tablas de hechos
SELECT 
 obj.name AS Tabla,
 stat.name AS Estadistica,
 sp.last_updated AS UltimaActualizacion,
 sp.rows AS FilasTotales,
 sp.modification_counter AS FilasModificadas,
 CAST(100.0 * sp.modification_counter / sp.rows AS DECIMAL(5,2)) AS PorcentajeCambio
FROM sys.stats AS stat
CROSS APPLY sys.dm_db_stats_properties(stat.object_id, stat.stats_id) AS sp
INNER JOIN sys.objects AS obj ON stat.object_id = obj.object_id
WHERE obj.type = 'U' 
 AND sp.modification_counter > 0
ORDER BY PorcentajeCambio DESC;

Si ves un PorcentajeCambio elevado en columnas que se usan frecuentemente en los WHERE de tus consultas de Power BI, tienes un problema de estadísticas. En este caso, la solución no es reiniciar el servidor (puedes leer más sobre esto en Lo que se pierde al reiniciar: cuándo fiarte de las DMVs y cuándo no), sino ejecutar un UPDATE STATISTICS con un muestreo representativo.

Identificando el Parameter Sniffing en el Plan de Ejecución

Si las estadísticas están al día pero la consulta sigue siendo lenta para ciertos parámetros, estamos ante un caso de sniffing. Para confirmarlo, debemos examinar el plan de ejecución gráfico (XML) y buscar dos propiedades clave en el operador raíz (normalmente el SELECT):

  • Parameter Compiled Value: El valor que se usó para generar el plan actual en caché.
  • Parameter Runtime Value: El valor que realmente se ha pasado en la ejecución que estás analizando.

Si el valor compilado es un Id_Producto muy poco frecuente y el de ejecución es un producto estrella, el plan será inadecuado. Para forzar al motor a ver la realidad sin alterar permanentemente el comportamiento, podemos usar el hint RECOMPILE temporalmente durante nuestras pruebas.

AtributoEstadísticas DesactualizadasParameter Sniffing
Síntoma PrincipalLentitud constante para cualquier parámetro.Lentitud intermitente o solo con ciertos valores.
CausaDesajuste entre metadatos e información real.Reutilización de un plan óptimo para otro valor.
Diagnósticosys.dm_db_stats_properties muestra datos viejos.Diferencia entre Compiled Value y Runtime Value.
Solución DirectaUPDATE STATISTICS con FULLSCAN.OPTION (RECOMPILE) o OPTIMIZE FOR.
Impacto en BIActualizaciones de Power BI lentas siempre.Actualizaciones que a veces fallan por timeout.

Decisiones de consultor: Cuándo actuar y qué evitar

En proyectos de alta criticidad, como los que gestionamos en sectores industriales o energía, no podemos permitirnos que un hint de consulta sea nuestra primera opción. Los hints son deudas técnicas. Si el modelo de datos cambia, el hint puede volverse contraproducente.

Antes de tocar el código T-SQL, asegúrate de que la arquitectura de datos es la correcta. Si estás sufriendo por el rendimiento en DirectQuery, te recomiendo revisar Las 50 Medidas y Patrones DAX que Destruyen el Rendimiento en DirectQuery (y cómo evitarlos). Muchas veces, lo que parece un problema de SQL es una consulta DAX ineficiente que genera un SQL monstruoso imposible de optimizar mediante estadísticas.

El peligro de UPDATE STATISTICS indiscriminado

Un error común es programar un UPDATE STATISTICS de toda la base de datos cada hora. Esto no solo consume recursos de IO y CPU, sino que invalida todos los planes de ejecución en la caché, obligando al motor a recompilar todo. Esto puede provocar picos de CPU masivos. La estrategia correcta es actualizar solo lo necesario:

-- Actualizar estadísticas de una tabla específica con muestreo completo
UPDATE STATISTICS dbo.Ventas_Detalle WITH FULLSCAN, COLUMNS; 
-- El uso de FULLSCAN es vital en columnas con sesgo de datos (skewed data)

Escenarios modernos: Microsoft Fabric y SQL Endpoint

Con la llegada de Microsoft Fabric, la gestión de estadísticas ha evolucionado. En el SQL Analytics Endpoint de Fabric, las estadísticas se crean y actualizan de forma automática en muchos casos, pero la lógica de fondo sigue siendo similar. Si trabajas con tablas Delta, la optimización de metadatos es el equivalente funcional. Para entender cómo Fabric maneja estos escenarios de rendimiento, consulta nuestra guía sobre Checkpoints de Delta en Fabric: Optimización de metadatos y velocidad de lectura.

Errores frecuentes que he visto en proyectos reales

  1. Confundir falta de índices con estadísticas viejas: Un escaneo de tabla (Table Scan) puede ser la decisión correcta si las estadísticas dicen que vas a leer el 90% de la tabla. Si en realidad vas a leer el 1%, el problema es la estadística. Si no tienes un índice adecuado para ese 1%, el problema es el diseño.
  2. Usar auto-update-statistics-async de forma inadecuada: Esta opción permite que la consulta se ejecute con estadísticas viejas mientras se actualizan de fondo. Es peligroso en procesos ETL de madrugada donde la precisión es más importante que la latencia inmediata.
  3. No vigilar el Gateway en Power BI: A veces la consulta en SQL es rápida, pero el problema de rendimiento se manifiesta en el refresco. Para descartar problemas de conectividad, revisa Actualización programada en Power BI: errores de Gateway, credenciales y optimización.

Checklist de diagnóstico rápido

  • [ ] Comprobar fecha de última actualización de estadísticas en tablas implicadas.
  • [ ] Comparar filas estimadas vs. filas reales en el plan de ejecución.
  • [ ] Verificar si el plan cambia drásticamente al usar OPTION (RECOMPILE).
  • [ ] Revisar el contador de modificaciones de la tabla desde el último análisis.
  • [ ] Validar que no hay una desfragmentación de índices pendiente que invalide el acceso.

Preguntas frecuentes

¿Es mejor actualizar estadísticas o reconstruir índices?

La reconstrucción de índices actualiza las estadísticas con un equivalente a FULLSCAN, pero es una operación mucho más pesada. Si el problema es solo la estimación de filas, un UPDATE STATISTICS es más rápido y menos intrusivo.

¿Por qué mi consulta es rápida en SSMS pero lenta en mi aplicación o Power BI?

Esto suele ser el síntoma definitivo de parameter sniffing. SSMS a menudo usa opciones de SET diferentes (como ARITHABORT), lo que fuerza la creación de un nuevo plan de ejecución independiente del que está usando Power BI o el Gateway.

¿Debo desactivar el auto-update statistics?

Casi nunca. Lo que debes hacer es complementar el auto-update con tareas de mantenimiento manuales en las ventanas de carga de datos, especialmente tras procesos masivos de ingesta en el Data Warehouse.

¿Cómo afecta el nivel de compatibilidad de la base de datos?

A partir de SQL Server 2014, se introdujo un nuevo Estimador de Cardinalidad (CE). A veces, simplemente cambiar el nivel de compatibilidad puede solucionar (o provocar) problemas de estimación. Es vital testear ambos niveles si las estadísticas parecen correctas pero el plan es pobre.


¿De cuánta utilidad te ha parecido este contenido?

¡Haz clic en una estrella para puntuarlo!

Puntuación media 0 / 5. Recuento de votos: 0

Hasta ahora, ¡no hay votos!. Sé el primero en puntuar este contenido.

Publicaciones Similares

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *