¿Cuándo sp_executesql actualiza el plan de consulta?

13

Tendrá que perdonar mi ingenuidad, ya que no soy un DBA, pero entiendo que con el tiempo las estadísticas de una base de datos cambian y se debe volver a compilar un procedimiento almacenado para mantener el plan de consultas actualizado con las últimas estadísticas.

Suponiendo que tengo un procedimiento almacenado en mi base de datos que se vuelve a compilar con las últimas estadísticas en un intervalo regular, ¿cuáles son las implicaciones de incluir el procedimiento almacenado en código y envolverlo en una sp_executesqldeclaración? ¿Pierdo la actualización del plan de consultas que solía ocurrir como parte de la recopilación del procedimiento?

Si hay algo más (aparte de los permisos) que debo tener en cuenta antes de realizar este cambio, agradecería sus ideas.

Leí esto en MSDN:

La capacidad del optimizador de consultas de SQL Server para hacer coincidir la nueva cadena de Transact-SQL con un plan de ejecución existente se ve obstaculizada por los valores de parámetros que cambian constantemente en el texto de la cadena, especialmente en declaraciones complejas de Transact-SQL.

Entonces, suponiendo que el procedimiento almacenado que intento en línea y envolver sp_executesqlrealmente contiene algunos parámetros, ¿esto dice que aunque mi plan de ejecución está en caché, estoy haciendo que sea más difícil para SQL Server encontrarlo y reutilizarlo?

james lewis
fuente

Respuestas:

7

La línea de MSDN habla sobre el uso EXEC(), como este:

SET @sql = 'SELECT foo FROM dbo.bar WHERE x = ''' + @x + ''';';
EXEC(@sql);

En mis pruebas, las versiones modernas de SQL Server todavía pueden reutilizar un plan como este, pero puede haber otras variables (como la versión o, por ejemplo, si agrega WHEREcláusulas condicionales basadas en la presencia de ciertos parámetros, en cuyo caso eso generará un plan diferente).

Si lo usa sp_executesql, los valores de los parámetros aún pueden causar problemas de detección de parámetros (al igual que con el SQL normal), pero esto no tiene nada que ver con si SQL Server puede reutilizar el plan. Este plan se usará una y otra vez, como si no lo hubiera usado sp_executesqlen absoluto, a menos que las variables que harían que una consulta directa se vuelva a compilar, en cuyo caso también se recompilará (esencialmente, SQL Server no almacene cualquier cosa con el plan que diga "esto se ejecutó desde sp_executesql, pero este no lo fue):

SET @sql = N'SELECT foo FROM dbo.bar WHERE x = @x;';
EXEC sp_executesql @sql, N'@x VARCHAR(32)', @x;

Como beneficio adicional, esto tiene protección incorporada contra SQL dinámico y evita que tenga que preocuparse por duplicar las comillas simples debido a los delimitadores de cadena. Blogueé sobre algo de esto aquí .

Si está teniendo problemas con el plan de reutilización y / o descubrimiento de parámetros, algunas cosas que deberán tener en cuenta son OPTION (RECOMPILE), OPTIMIZE FOR, optimize for ad hoc workloadsy simple/forced parameterization. Abordé algunas preguntas similares en respuesta a un reciente webcast aquí, puede valer la pena echar un vistazo:

http://sqlperformance.com/performance-palooza

La esencia es: no tengas miedo de usarlo sp_executesql, solo úsalo cuando lo necesites y solo gasta energía optimizándolo en exceso cuando tengas un problema de rendimiento real. El ejemplo anterior es terrible porque no hay razón para usar SQL dinámico aquí: he escrito esta respuesta asumiendo que tiene un caso de uso legítimo.

Aaron Bertrand
fuente
2

Las consultas que se ejecutan a través de sp_executesql siguen las mismas reglas de los planes de ejecución que las consultas normales que no se ejecutan a través de sp_executesql. Si el texto de la consulta cambia, se crea un nuevo plan. Si el texto no cambia debido al usuario de los parámetros, el plan se reutiliza. Cuando se actualizan las estadísticas, los planes caducan y se generan nuevos planes la próxima vez que se ejecuta la consulta.

mrdenny
fuente
Gracias por su respuesta, hice una edición con respecto a los parámetros, ya que ahora me doy cuenta de que cada vez que llamo a sp_ExecuteSql usaré una cadena diferente como consulta debido al hecho de que, desde la perspectiva del servidor SQL, he reemplazado los parámetros con valores codificados (se ingresarán en el código antes de enviar mi consulta al servidor SQL). ¿Conoces alguna forma de evitar esto? ¿Declarar variables en mi declaración sql en línea ayudaría al optimizador de consultas a encontrar mi plan de consultas en caché?
james lewis