sql >> Base de Datos >  >> RDS >> Sqlserver

SQL Server Internals:plan de almacenamiento en caché Pt. II – Planes de Recompilación

Esto es parte de una serie de almacenamiento en caché del plan interno de SQL Server. Asegúrese de leer la primera publicación de Kalen sobre este tema.

SQL Server existe desde hace más de 30 años y yo he estado trabajando con SQL Server durante casi el mismo tiempo. He visto muchos cambios a lo largo de los años (¡y décadas!) y versiones de este increíble producto. En estas publicaciones, compartiré con ustedes cómo veo algunas de las características o aspectos de SQL Server, a veces junto con un poco de perspectiva histórica

En mi artículo anterior , hablé sobre los diagnósticos del servidor SQL, incluidas las diversas opciones que tiene SQL Server para reutilizar un plan de consulta. Examinamos tres tipos de planes de consulta:adhoc, preparados y de procedimiento. Terminé la discusión con una mirada a la reutilización inapropiada de un plan, lo que puede ocurrir cuando SQL Server aplica el rastreo de parámetros en situaciones incorrectas. Si un plan se basa en un valor inicial que hace que el optimizador genere un plan apropiado para ese valor, y luego se usa el mismo plan para un valor diferente, es posible que el plan ya no sea óptimo.

Entonces, ¿qué podemos hacer cuando la detección de parámetros es un problema? Podemos obligar a SQL Server a idear un nuevo plan. Por lo general, llamamos al acto de idear un nuevo plan "recompilar", pero probablemente debería llamarse "reoptimización". Sin embargo, la mayoría de la gente usa el término "recompilar", así que eso es lo que usaré aquí.

Si el uso inapropiado de la detección de parámetros es un problema, una solución simple es simplemente decirle a SQL Server que presente un nuevo plan. Para declaraciones individuales, como con planes PREPARADOS que se han parametrizado automáticamente, podemos agregar la sugerencia RECOMPILE a una consulta. Usando FORZADO parametrizado (discutido en el artículo anterior), esta consulta será parametrizada.

SELECT * FROM dbo.newsales 
WHERE SalesOrderID < @num;

Si queremos asegurarnos de obtener un nuevo plan cada vez que ejecutamos esta consulta, con valores potencialmente muy diferentes para @num, podemos agregar la sugerencia RECOMPILE como se muestra:

SELECT * FROM dbo.newsales
  WHERE SalesOrderID < @num
OPTION (RECOMPILE);

Para procedimientos almacenados, tenemos tres opciones. Primero, podemos determinar si la recompilación realmente ayudará al rendimiento ejecutando el procedimiento con la opción RECOMPILE:

EXEC get_sales_range 66666 WITH RECOMPILE;

Esta opción hará que se genere un nuevo plan solo para esta ejecución. No se guardará y ciertamente no se reutilizará. El valor de usecount que se muestra en sp_cacheobjects (descrito en la publicación anterior) para el procedimiento no aumentará ya que el plan original no se está reutilizando.

En segundo lugar, si encontramos que ejecutar WITH RECOMPILE ayuda, podríamos considerar recrear el procedimiento con la opción RECOMPILE, en cuyo caso nunca reutilizará el plan y el procedimiento no aparecerá en absoluto en el caché del plan.

DROP PROC IF EXISTS get_sales_range;GO
CREATE PROC get_sales_range
   @num int
WITH RECOMPILE
AS
    SELECT * FROM dbo.newsales
    WHERE SalesOrderID < @num;
GO

Para mi pequeño y simple procedimiento, usar la opción CON RECOMPILACIÓN para todo el procedimiento podría tener sentido. Pero si el procedimiento es más complejo, puede que no tenga sentido volver a compilar todo el procedimiento porque una declaración está causando problemas. Entonces, la tercera opción es usar la sugerencia RECOMPILE para una declaración dentro del procedimiento, por lo que se ve así:

DROP PROC IF EXISTS get_sales_range;
GO
CREATE PROC get_sales_range
   @num int
AS
    SELECT * FROM dbo.newsales
    WHERE SalesOrderID < @num
    OPTION (RECOMPILE);
GO

El uso de una de estas opciones de RECOMPILE puede obligar a SQL Server a crear un nuevo plan a pedido suyo. Ahora, veremos cuándo sus diagnósticos de SQL Server presentan un nuevo plan cuando no lo solicita, es decir, ¿cuándo ocurre la recompilación automática de un plan existente?


La recompilación automática de un plan ocurre en dos tipos de situaciones:

  • Primero, si el optimizador determina que el plan existente ya no es correcto, generalmente debido a un cambio en las definiciones de los objetos, deberá crear un nuevo plan. Por ejemplo, si tiene un plan para una consulta que selecciona de TableA y luego elimina varias columnas o cambia los tipos de datos de las columnas en TableA, SQL Server volverá a compilar la consulta para generar un plan que refleje los cambios de DDL.
  • La segunda situación en la que se produce la recompilación automática es cuando SQL Server determina que es posible que el plan ya no sea óptimo debido a un cambio en las estadísticas. En la mayoría de los casos, si las estadísticas de cualquiera de las columnas o índices se han actualizado desde la última vez que se compiló el plan, se volverá a compilar. Pero esto lleva a otra pregunta. ¿Cuándo se actualizan las estadísticas? Las estadísticas se pueden actualizar automáticamente cuando han cambiado suficientes filas en las columnas relevantes. ¿Cuántos son suficientes? Hablamos de eso en breve.

De forma predeterminada, SQL Server actualizará las estadísticas automáticamente debido a una opción de base de datos que está activada de forma predeterminada. Pero si es el propietario de una base de datos (o un SQL 'sa', que aparece como propietario en todas las bases de datos), puede cambiar las opciones. Una de las opciones se llama AUTO_UPDATE_STATISTICS y otra se llama AUTO_UPDATE_STATISTICS_ASYNC. La opción AUTO_UPDATE_STATISTICS está activada en la base de datos tempdb, por lo que cada base de datos nueva hereda esta opción. Cuando esta opción está activada y el motor de ejecución de consultas detecta cambios en un número suficiente de filas mientras se procesa una consulta, la ejecución se detendrá mientras se actualizan las estadísticas y luego se vuelve a compilar la consulta. La otra opción, AUTO_UPDATE_STATISTICS_ASYNC, puede tener un efecto menor en el tiempo de ejecución de la consulta porque la ejecución no se detiene, a costa de usar un posible plan subóptimo. Con la segunda opción, si el motor de ejecución detecta la necesidad de actualizar las estadísticas, se activa un subproceso en segundo plano para realizar la actualización y el subproceso principal continúa ejecutando la consulta con las estadísticas originales y el plan original. La próxima consulta que acceda a las tablas afectadas y vea las estadísticas actualizadas volverá a compilar la consulta, pero no se detendrá y actualizará las estadísticas en medio de la ejecución.

Hay algunas situaciones más, así como algunas sugerencias de consulta que controlan si los planes se vuelven a compilar o no, así que les mostraré un diagrama de flujo. Compartiré con ustedes un diagrama de flujo que creé para mis clases de capacitación sobre los aspectos internos de SQL Server.

La flecha es donde SQL Server comienza a procesar su lote. Primero verifica si ya existe un plan para su lote en caché, y si la respuesta es NO, sigue la flecha hacia la derecha y compila un plan. El plan se coloca en caché y, a continuación, SQL Server se inicia de nuevo. Sí, el plan debe estar en caché esta vez, por lo que sigue la flecha hacia abajo y pregunta si se ha utilizado una pista llamada MANTENER PLAN. En caso afirmativo, SQL Server comienza a ejecutar el plan de inmediato y no realiza más comprobaciones.

La siguiente pregunta es si se han realizado cambios en DDL. Si no, pregunta sobre varias otras situaciones de las que no voy a poder hablar en este artículo. De hecho, realmente no voy a pasar por todas las opciones aquí. Te lo dejo a ti. Pero si tiene alguna pregunta o confusión, no dude en hacerla en la sección de comentarios aquí, o enviarme un tweet a @sqlqueen. Señalaré la pregunta en el extremo derecho:¿Está AUTO_STATS_ASYNC ENCENDIDO? Aquí puede ver que si la respuesta es SÍ, hay dos acciones. Una rama simplemente comienza a ejecutarse con el plan existente y la otra es el subproceso en segundo plano que actualiza las estadísticas pero luego no hace nada más. La siguiente consulta encontrará el cuadro de decisión en el medio "Hay nuevas estadísticas disponibles" y debe responder SÍ, por lo que la consulta se volverá a compilar.

La única otra cosa de la que hablaré es la pregunta "¿Hay estadísticas obsoletas?" Esto básicamente significa que las estadísticas están desactualizadas porque se han realizado demasiados cambios. Así que ahora podemos hablar de cuántos son demasiados.

Aunque se usan diferentes valores para tablas muy pequeñas, para cualquier tabla con más de 500 filas, antes de SQL Server 2016, las estadísticas se consideraban "obsoletas" cuando la cantidad de cambios en la columna en la que se basaban superaba los 20. % del número de filas de la tabla. Entonces, para una tabla de 1000 filas, esto podría significar 200 inserciones, 200 actualizaciones o 200 eliminaciones. Podrían ser cambios de 200 filas o 5 filas actualizadas 40 veces cada una. SQL Server incluso nos brinda una función que informa cuántos cambios se han realizado. Deberá buscar el número stats_id de las estadísticas que le interesan, que sería index_id si las estadísticas pertenecen a un índice. El stats_id se puede encontrar en la vista llamada sys.stats. En mi tabla de ventas de noticias, uso esta consulta para encontrar que stats_id para el índice en la columna SubTotal es 3.

SELECT name, stats_id FROM sys.stats
WHERE object_id = object_id('newsales');

Entonces puedo usar ese valor para ver la cantidad de cambios. Permítanme actualizar algunas filas primero:

UPDATE newsales
SET SubTotal = SubTotal * 0.9
WHERE SalesOrderID < 45200
(1541 filas afectadas)

SELECT * FROM sys.dm_db_stats_properties(object_id('newsales'), 3);  

De hecho, el 20% es un número GRANDE. Y para muchas tablas, las consultas pueden beneficiarse de estadísticas actualizadas con mucho menos del 20 % de las filas actualizadas. A partir de 2008R2 SP1, SQL Server incluyó un Traceflag que podría usar para cambiar el número de filas para que sea una escala móvil, como se muestra en el siguiente gráfico:

A partir de SQL Server 2016, este nuevo algoritmo con la escala móvil se usa de forma predeterminada, siempre que tenga un nivel de compatibilidad 130 o superior.

La mayoría de las recompilaciones automáticas de planes de consulta se deben a cambios en las estadísticas. Pero como mencioné anteriormente, esa no es la única razón para una recompilación. Pero dado que es el más común, puede ser muy útil estar al tanto de cuándo y cómo se actualizan las estadísticas y asegurarse de que las estadísticas en sus tablas críticas se actualicen con la frecuencia suficiente para asegurarse de obtener los mejores planes.

Analice los datos de rendimiento automáticamente para realizar diagnósticos del servidor SQL para resolver problemas rápidamente e identificar los servidores donde se origina la degradación del rendimiento. Comience a usar Spotlight Cloud hoy: