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

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

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.

Consulte los blogs recientes de Kalen sobre Operadores Problemáticos aquí.

Los planes para el diagnóstico del servidor SQL pueden ser costosos de crear, ya que el optimizador de consultas debe poder encontrar un buen plan para cualquier consulta legal que se envíe. El optimizador evalúa múltiples órdenes de unión, múltiples índices. y varios tipos de algoritmos de unión y agrupación, según su consulta y las tablas involucradas. Si se vuelve a ejecutar la misma consulta, SQL Server puede ahorrar muchos recursos al reutilizar un plan existente. Pero no siempre es posible reutilizar un plan existente, y no siempre es bueno hacerlo. En los próximos dos artículos, veremos cuándo se reutiliza un plan y cuándo se vuelve a compilar.

Primero, veremos los diferentes tipos de planes y la vista de metadatos que uso con más frecuencia para ver qué hay en la memoria caché de mi plan. He escrito una vista propia que proporciona la información que encuentro más útil con mayor frecuencia. SQL Server almacena en caché seis tipos diferentes de planes de consulta, pero solo dos se usan normalmente para el ajuste de caché de planes. Estos son PLAN COMPILADO y TALÓN DEL PLAN COMPILADO. Mi vista filtra todos menos estos dos tipos de objetos de caché. Los PLANES COMPILADOS vienen en tres variedades:AD HOC, PREPARADOS y PROC. Comentaré sobre los tres tipos.

Incluso si solo estamos viendo PLANES COMPILADOS, todavía hay muchos planes en caché que generalmente deben ignorarse, ya que son generados por el propio SQL Server. Estos incluyen planes que buscan flujos de archivos o índices de búsqueda de texto completo o consultas internas que funcionan con OLTP en memoria. Por lo tanto, mi vista agrega filtros para tratar de descartar la mayoría de los planes que no me interesan. Puede descargar un script para crear esta vista, llamado sp_cacheobjects , desde aquí.

Incluso con todos los filtros que usa mi vista, todavía hay algunas de las propias consultas internas de SQL Server en caché; Por lo general, borro el caché del plan con frecuencia cuando hago pruebas en esta área. La forma más sencilla de borrar TODOS los planes del caché es con el comando:DBCC FREEPROCCACHE.

Planes Compilados Adhoc

El tipo de plan más simple es Adhoc. Esto se usa para consultas básicas que no encajan en otra categoría. Si descargó mi script y creó mi vista sp_cacheobjects, puede ejecutar lo siguiente. Cualquier versión de la base de datos AdventureWorks debería funcionar. Este script hace una copia de una tabla y crea un par de índices únicos en ella. También masajea la cantidad SubTotal para eliminar cualquier dígito decimal.

USE AdventureWorks2016;
GO
DROP TABLE IF EXISTS newsales;
GO
-- Make a copy of the Sales.SalesOrderHeader table
SELECT * INTO dbo.newsales
FROM Sales.SalesOrderHeader;
GO
UPDATE dbo.newsales
SET SubTotal = cast(cast(SubTotal as int) as money);
GO
CREATE UNIQUE index newsales_ident
    ON newsales(SalesOrderID);
GO
CREATE INDEX IX_Sales_SubTotal ON newsales(SubTotal);
GO
-- Adhoc query plan reuse
DBCC FREEPROCCACHE;
GO
-- adhoc query
SELECT * FROM dbo.newsales
WHERE SubTotal = 4;
GO
SELECT * FROM sp_cacheobjects;
GO

En mi salida, ves dos planes Adhoc. Uno es para la declaración SELECT de newsales table, y el otro es para SELECT de mis sp_cacheobjects vista. Debido a que el plan se almacena en caché, si se vuelve a ejecutar EXACTAMENTE la misma consulta, se puede reutilizar el mismo plan y verá los conteos de uso incremento de valor Sin embargo, hay una trampa. Para poder reutilizar un plan Adhoc, la cadena SQL debe ser exactamente igual. Si cambia algún carácter en el SQL, la consulta no se reconoce como la misma consulta y se genera un nuevo plan. Si agrego un espacio, incluyo el comentario o un nuevo salto de línea, no es la misma cadena. Si cambio el caso, eso significa que hay diferentes valores de código ASCII, por lo tanto, no es la misma cadena.

Puede probar esto usted mismo ejecutando diferentes variaciones de mi primera declaración SELECT de newsales mesa. Verá una fila diferente en el caché para cada uno. Después de ejecutar varias variaciones:cambiar el número que estaba buscando, cambiar el caso, agregar el comentario y una nueva línea, veo lo siguiente en caché. El SELECT desde mi punto de vista se está reutilizando, pero todo lo demás tiene un usecounts valor de 1.

Un requisito adicional para la reutilización del plan de consulta Adhoc es que la sesión que ejecuta la consulta debe tener las mismas opciones SET en vigor . Hay otra columna en la salida que puede ver a la derecha del texto de la consulta, llamada SETOPTS. Esta es una cadena de bits con un bit para cada opción SET relevante. Si cambia una de las opciones, por ejemplo, SET ANSI_NULLS OFF, la cadena de bits cambiará y no se podrá reutilizar el mismo plan con la cadena de bits original.

Planes Compilados Preparados

El segundo tipo de plan compilado en caché es un plan PREPARADO. Si su consulta cumple con un determinado conjunto de requisitos. De hecho, se puede parametrizar automáticamente. Aparece en los metadatos como PREPARADO y la cadena SQL muestra un marcador de parámetro. Aquí hay un ejemplo:

El plan PREPARADO muestra el marcador de parámetro como @1 y no incluye el valor real. Observe que hay una fila para una consulta ADHOC con un valor real de 5555, pero en realidad es solo una "capa" de la consulta real. No almacena en caché todo el plan, sino solo la consulta y algunos detalles de identificación, para ayudar al procesador de consultas a encontrar el plan parametrizado en la memoria caché. Observe el tamaño (páginas utilizadas ) es mucho más pequeño que el plan PREPARADO.

El modo de parametrización predeterminado, llamado parametrización SIMPLE, es extremadamente estricto sobre qué planes se pueden parametrizar. En realidad, solo las consultas más simples son parametrizables de forma predeterminada. Las consultas que contienen JOIN, GROUP BY, OR y muchas otras construcciones de consulta relativamente comunes evitan que se parametrice una consulta. Además de no tener ninguna de estas construcciones, lo más importante para la parametrización SIMPLE es que la consulta sea SEGURA. Esto significa que solo hay un plan posible, independientemente de los valores que se pasen para cualquier parámetro. (Por supuesto, una consulta sin ningún parámetro también podría ser SEGURA). Mi consulta busca una coincidencia exacta en la columna SalesOrderID , que tiene un índice único. Entonces, el índice no agrupado existente podría usarse para encontrar cualquier fila coincidente. No importa qué valor use, 55555 u otro, nunca habrá más de una fila, lo que significa que el plan seguirá siendo bueno.

En mi ejemplo de plan de consulta Adhoc, estaba buscando valores coincidentes para SubTotal . Algunos Subtotal los valores ocurren unas pocas veces o no ocurren en absoluto, por lo que un índice no agrupado sería bueno. Pero otros valores podrían ocurrir muchas veces, por lo que el índice NO sería útil. Por lo tanto, el plan de consulta no es SEGURO y la consulta no se puede parametrizar. Es por eso que vimos un plan Adhoc para mi primer ejemplo.

SI tiene consultas con JOIN u otras construcciones no permitidas, puede decirle a SQL Server que sea más agresivo en la parametrización cambiando una opción de la base de datos:

ALTER DATABASE AdventureWorks2016 SET parameterization FORCED;
GO

Establecer su base de datos en parametrización FORZADA significa que SQL Server parametrizará muchas más consultas, incluidas aquellas con JOIN, GROUP BY, OR, etc. Pero también significa que SQL Server puede parametrizar una consulta que no es SEGURA. Puede generar un plan que sea bueno cuando solo se devuelven unas pocas filas y luego reutilizar el plan cuando se devuelven muchas filas. Esto puede terminar con un rendimiento muy por debajo del óptimo.

Una última opción para un plan preparado es preparar un plan explícitamente. Este comportamiento generalmente se invoca a través de una aplicación con SQLPrepare y SQLExecute API. Usted especifica cuál es la consulta con marcas de parámetros, especifica los tipos de datos y especifica los valores específicos a usar. La misma consulta se puede ejecutar de nuevo con diferentes valores específicos y se utilizará el plan existente. Aunque el uso de planes preparados explícitamente puede ser posible en aquellos casos en los que SQL Server no está parametrizando y desearía que lo hiciera, no impide que SQL Server use un plan que NO es bueno para los parámetros posteriores. Debe probar sus consultas con muchos valores de entrada diferentes y asegurarse de obtener el rendimiento esperado cuando se reutilice un plan.

Los metadatos (por ejemplo, mis sp_cacheobjects view) solo muestra PREPARADO para los tres tipos de planes:autoparametrización FORZADA y SIMPLE y parametrización EXPLÍCITA.

Planes compilados de Proc

El tipo de objeto final El valor de planes compilados es para un procedimiento almacenado, que se muestra como Proc. Cuando es posible, los procedimientos almacenados son la mejor opción para el código reutilizable, debido a su facilidad de administración desde el propio servidor, pero eso no significa que siempre ofrezcan el mejor rendimiento. Al igual que usar la opción de parametrización FORZADA (y también la parametrización explícita), los procedimientos almacenados usan la "exploración de parámetros". Esto significa que el primer valor de parámetro pasado determina el plan. Si las ejecuciones posteriores funcionan bien con el mismo plan, entonces la detección de parámetros no es un problema y, de hecho, puede ser beneficiosa porque nos ahorra el costo de volver a compilar y optimizar. Sin embargo, si las ejecuciones posteriores con valores diferentes no deberían usar el plan original, entonces tenemos un problema. Te mostraré un ejemplo de rastreo de parámetros que causa un problema

Crearé un procedimiento almacenado basado en las newsales tabla que usamos antes. El procedimiento tendrá una única consulta, que filtra en función del SalesOrderID columna, en la que construimos un índice no agrupado. La consulta se basará en una desigualdad, por lo que para algunos valores, la consulta puede devolver solo unas pocas filas y usar el índice, y para otros valores, la consulta puede devolver MUCHAS filas. En otras palabras, la consulta no es SEGURA.

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

Usaré la opción SET STATISTICS IO ON para ver cuánto trabajo se está realizando cuando se ejecuta el procedimiento. Primero, lo ejecutaré con un parámetro que solo devuelve unas pocas filas:

SET STATISTICS IO ON
GO
EXEC get_sales_range 43700;
GO

El valor STATISTICS IO informa que se necesitaron 43 lecturas lógicas para devolver 41 filas. Esto es normal para un índice no agrupado. Ahora ejecutamos el procedimiento nuevamente con un valor mucho mayor.

EXEC get_sales_range 66666;
GO
SELECT * FROM sp_cacheobjects;
GO
This time, we see that SQL Server used a whole lot more reads:

De hecho, un escaneo de tabla en las ventas de noticias table solo toma 843 lecturas, por lo que este es un rendimiento mucho peor que un escaneo de tabla. Los sp_cacheobjects view nos muestra que el plan PROC ha sido reutilizado para esta segunda ejecución. Este es un ejemplo de cuando la detección de parámetros NO es algo bueno.

Entonces, ¿qué podemos hacer cuando la detección de parámetros es un problema? En la próxima publicación, le diré cuándo SQL Server presenta un nuevo plan y no reutiliza los antiguos. Veremos cómo puede forzar (o fomentar) la recompilación y también veremos cuándo SQL Server vuelve a compilar automáticamente sus consultas.

Spotlight Cloud puede revolucionar la supervisión del rendimiento y el diagnóstico del servidor SQL. Comience con su prueba gratuita usando el siguiente enlace: