stored resueltos procedimientos procedimiento español ejercicios ejemplo ejecutar desde almacenados almacenado sql-server tsql sql-server-2008-r2 query-optimization

sql server - resueltos - Optimización de los planes de ejecución para consultas de T-SQL parametrizadas que contienen funciones de ventana



procedimientos almacenados sql server pdf (3)

Creo que en este caso particular puede deberse a que los tipos de datos entre sus parámetros y su tabla no coinciden exactamente, por lo que SQL Server tiene que hacer una conversión implícita que no es una operación sargable.

Compruebe los tipos de datos de su tabla y haga que sus parámetros sean del mismo tipo. O haz el elenco tú mismo fuera de la consulta.

EDITAR: Actualicé el código de ejemplo y proporcioné implementaciones completas de tablas y vistas para referencia, pero la pregunta esencial permanece sin cambios.

Tengo una vista bastante compleja en una base de datos que estoy intentando consultar. Cuando intento recuperar un conjunto de filas de la vista mediante la codificación rígida de la cláusula WHERE a valores de clave externa específicos, la vista se ejecuta muy rápidamente con un plan de ejecución óptimo (los índices se utilizan correctamente, etc.)

SELECT * FROM dbo.ViewOnBaseTable WHERE ForeignKeyCol = 20

Sin embargo, cuando intento agregar parámetros a la consulta, de repente, mi plan de ejecución se desmorona. Cuando ejecuto la consulta a continuación, obtengo escaneos de índice en lugar de búsquedas por todas partes y el rendimiento de la consulta es muy bajo.

DECLARE @ForeignKeyCol int = 20 SELECT * FROM dbo.ViewOnBaseTable WHERE ForeignKeyCol = @ForeignKeyCol

Estoy usando SQL Server 2008 R2. ¿Qué da aquí? ¿De qué se trata el uso de parámetros que están causando un plan subóptimo? Cualquier ayuda sería muy apreciada.

Para referencia, aquí están las definiciones de objetos para las que recibo el error.

CREATE TABLE [dbo].[BaseTable] ( [PrimaryKeyCol] [uniqueidentifier] PRIMARY KEY, [ForeignKeyCol] [int] NULL, [DataCol] [binary](1000) NOT NULL ) CREATE NONCLUSTERED INDEX [IX_BaseTable_ForeignKeyCol] ON [dbo].[BaseTable] ( [ForeignKeyCol] ASC ) CREATE VIEW [dbo].[ViewOnBaseTable] AS SELECT PrimaryKeyCol, ForeignKeyCol, DENSE_RANK() OVER (PARTITION BY ForeignKeyCol ORDER BY PrimaryKeyCol) AS ForeignKeyRank, DataCol FROM dbo.BaseTable

Estoy seguro de que la función de la ventana es el problema, pero estoy filtrando mi consulta por un solo valor por el que la función de la ventana está particionando, por lo que esperaría que el optimizador filtre primero y luego ejecute la función de la ventana. Lo hace en el ejemplo codificado, pero no en el ejemplo parametrizado. A continuación se muestran los dos planes de consulta. El plan superior es bueno y el plan inferior es malo.


Cuando utilice la OPTION (RECOMPILE) asegúrese de mirar el plan posterior a la ejecución ("real") en lugar del plan anterior a la ejecución ("estimado"). Algunas optimizaciones solo se aplican cuando ocurre la ejecución:

DECLARE @ForeignKeyCol int = 20; SELECT ForeignKeyCol, ForeignKeyRank FROM dbo.ViewOnBaseTable WHERE ForeignKeyCol = @ForeignKeyCol OPTION (RECOMPILE);

Plan de pre-ejecución:

Plan post ejecución:

Probado en SQL Server 2012 compilación 11.0.3339 y SQL Server 2008 R2 compilación 10.50.4270

Antecedentes y limitaciones

Cuando se agregaron funciones de ventanas en SQL Server 2005, el optimizador no tenía forma de pasar las selecciones más allá de estas nuevas proyecciones de secuencia. Para abordar algunos escenarios comunes en los que esto causó problemas de rendimiento, SQL Server 2008 agregó una nueva regla de simplificación, SelOnSeqPrj , que permite la SelOnSeqPrj selecciones adecuadas donde el valor es una constante. Esta constante puede ser un literal en el texto de consulta, o el valor OPTION (RECOMPILE) de un parámetro obtenido a través de OPTION (RECOMPILE) . No hay ningún problema en particular con los NULLs aunque es posible que la consulta deba tener ANSI_NULLS OFF para ver esto. Que yo sepa, aplicar la simplificación a valores constantes es una limitación de la implementación; no hay ninguna razón particular por la que no se pueda extender para trabajar con variables. Mi recuerdo es que la regla SelOnSeqPrj los problemas de rendimiento más comunes.

Parametrización

La regla SelOnSeqPrj no se aplica cuando una consulta se parametriza automáticamente con éxito . No hay una manera confiable de determinar si una consulta se parametrizó automáticamente en SSMS, solo indica que se intentó realizar un auto-parámetro. Para ser claros, la presencia de marcadores de posición como [@0] solo muestra que se intentó la parametrización automática. Una forma confiable de saber si un plan preparado se almacenó en la memoria caché para reutilizarlo es inspeccionar el caché del plan, donde el ''identificador del plan parametrizado'' proporciona el vínculo entre los planes preparados y ad-hoc.

Por ejemplo, la siguiente consulta parece ser auto-parametrizada en SSMS:

SELECT * FROM dbo.ViewOnBaseTable WHERE ForeignKeyCol = 20;

Pero el caché del plan muestra lo contrario:

WITH XMLNAMESPACES ( DEFAULT ''http://schemas.microsoft.com/sqlserver/2004/07/showplan'' ) SELECT parameterized_plan_handle = deqp.query_plan.value(''(//StmtSimple)[1]/@ParameterizedPlanHandle'', ''nvarchar(64)''), parameterized_text = deqp.query_plan.value(''(//StmtSimple)[1]/@ParameterizedText'', ''nvarchar(max)''), decp.cacheobjtype, decp.objtype, decp.plan_handle FROM sys.dm_exec_cached_plans AS decp CROSS APPLY sys.dm_exec_sql_text(decp.plan_handle) AS dest CROSS APPLY sys.dm_exec_query_plan(decp.plan_handle) AS deqp WHERE dest.[text] LIKE N''%ViewOnBaseTable%'' AND dest.[text] NOT LIKE N''%dm_exec_cached_plans%'';

Si la opción de la base de datos para la parametrización forzada está habilitada, obtenemos un resultado parametrizado, donde no se aplica la optimización:

ALTER DATABASE Sandpit SET PARAMETERIZATION FORCED; DBCC FREEPROCCACHE; SELECT * FROM dbo.ViewOnBaseTable WHERE ForeignKeyCol = 20;

La consulta de caché del plan ahora muestra un plan en caché parametrizado, vinculado por el identificador del plan parametrizado:

Solución

Siempre que sea posible, mi preferencia es volver a escribir la vista como una función de valores de tabla en línea, donde la posición deseada de la selección se puede hacer más explícita (si es necesario):

CREATE FUNCTION dbo.ParameterizedViewOnBaseTable (@ForeignKeyCol integer) RETURNS TABLE WITH SCHEMABINDING AS RETURN SELECT bt.PrimaryKeyCol, bt.ForeignKeyCol, ForeignKeyRank = DENSE_RANK() OVER ( PARTITION BY bt.ForeignKeyCol ORDER BY bt.PrimaryKeyCol), bt.DataCol FROM dbo.BaseTable AS bt WHERE bt.ForeignKeyCol = @ForeignKeyCol;

La consulta se convierte en:

DECLARE @ForeignKeyCol integer = 20; SELECT pvobt.* FROM dbo.ParameterizedViewOnBaseTable(@ForeignKeyCol) AS pvobt;

Con el plan de ejecución:


Siempre se puede ir por el camino de la CRUZ.

ALTER VIEW [dbo].[ViewOnBaseTable] AS SELECT PrimaryKeyCol, ForeignKeyCol, ForeignKeyRank, DataCol FROM ( SELECT DISTINCT ForeignKeyCol FROM dbo.BaseTable ) AS Src CROSS APPLY ( SELECT PrimaryKeyCol, DENSE_RANK() OVER (ORDER BY PrimaryKeyCol) AS ForeignKeyRank, DataCol FROM dbo.BaseTable AS B WHERE B.ForeignKeyCol = Src.ForeignKeyCol ) AS X