2008-10-17 13 views
60

Hace un tiempo tuve una consulta que corrí bastante para uno de mis usuarios. Aún se estaba desarrollando y modificando, pero finalmente se estabilizó y ejecutó con bastante rapidez, por lo que creamos un procedimiento almacenado a partir de él.Sniffing de parámetros (o Spoofing) en SQL Server

Hasta ahora, muy normal.

El procedimiento almacenado, sin embargo, fue lento. No hay diferencia material entre la consulta y el proceso, pero el cambio de velocidad fue masivo.

[fondo, nos estamos quedando SQL Server 2005.]

Un DBA agradable local (que ya no trabaja aquí) tomó una mirada en el procedimiento almacenado y dijo "parámetro de suplantación de identidad!" (Editar: aunque parece que es, posiblemente, también conocido como 'descubrimiento de parámetros', lo que podría explicar la escasez de Google golpea cuando traté de buscar a cabo.)

Se resumieron algunos de los procedimientos almacenados a una en segundo lugar, envolví la llamada a este nuevo proceso interno en el proceso externo preexistente, llamado el externo y, listo, fue tan rápido como la consulta original.

Entonces, ¿qué da? ¿Alguien puede explicar la suplantación de parámetros?

crédito de bonificación sobre

  • destacando cómo evitarlo
  • sugiriendo cómo reconocer posible causa
  • discutir estrategias alternativas, por ejemplo, estadísticas, índices, claves, para mitigar la situación
+0

No es solo una posibilidad, es una certeza, no existe la parametrización de parámetros. Es parámetro oliendo. – ErikE

Respuesta

52

FYI - debe tener en cuenta otra cosa cuando se trabaja con SQL 2005 y procs almacenados con parámetros.

SQL Server compilará el plan de ejecución del proceso almacenado con el primer parámetro que se use. Por lo tanto, si ejecuta esto:

usp_QueryMyDataByState 'Rhode Island' 

El plan de ejecución funcionará mejor con los datos de un estado pequeño.Pero si alguien se da la vuelta y corre:

usp_QueryMyDataByState 'Texas' 

El plan de ejecución diseñado para los datos de Rhode Island-de tamaño puede no ser tan eficaz con los datos del tamaño de Texas. Esto puede producir resultados sorprendentes cuando se reinicia el servidor, ya que el plan de ejecución recién generado se dirigirá a cualquier parámetro que se use primero, no necesariamente el mejor. El plan no se volverá a compilar hasta que haya una gran razón para hacerlo, como si se reconstruyeran las estadísticas.

Aquí es donde entran en juego los planes de consulta, y SQL Server 2008 ofrece muchas características nuevas que ayudan a los DBA a fijar un plan de consulta en particular a largo plazo sin importar qué parámetros se llamen primero.

Mi preocupación es que cuando reconstruiste el proceso almacenado, forzaste la recompilación del plan de ejecución. Lo llamó con su parámetro favorito, y luego, por supuesto, fue rápido, pero el problema puede no haber sido el proceso almacenado. Pudo haber sido que el proceso almacenado fue recompilado en algún momento con un conjunto inusual de parámetros y, por lo tanto, un plan de consulta ineficiente. Es posible que no hayas arreglado nada y que puedas enfrentar el mismo problema la próxima vez que el servidor se reinicie o el plan de consulta se vuelva a compilar.

+2

entonces ... ¿cómo evitarlo? – thomaspaulb

+3

Recoja el excelente libro de Grant Fritchey SQL Server 2008 Query Performance Destilado donde revisa todas sus opciones. Aunque dice 2008, también es excelente para 2005. –

+0

Recomiendo buscar dos soluciones posibles, la primera que he probado y visto funcionar, la segunda sospecho que funcionaría pero no la he intentado en la práctica. –

26

Sí, creo que se refiere al parámetro sniffing, que es una técnica que el optimizador de SQL Server usa para tratar de determinar los valores/rangos de parámetros para que pueda elegir la mejor ejecución plan para su consulta. En algunos casos, el SQL Server hace un trabajo pobre en el parámetro sniffing & no elige el mejor plan de ejecución para la consulta.

Creo que este artículo del blog http://blogs.msdn.com/queryoptteam/archive/2006/03/31/565991.aspx tiene una buena explicación.

Parece que el DBA en su ejemplo eligió la opción # 4 para mover la consulta a otro sproc a un contexto de procedimiento separado.

Usted podría tener también utilizaron el con recompilación en el sproc original o utilizó el Optimizar para opción en el parámetro.

+1

+1, pero tenga en cuenta que el "con recompilación" podría tener problemas de rendimiento de sí mismo. Tiendo a probar la opción n. ° 4 primero ... –

+0

Mi comprensión de las uniones es el tipo de combinación (combinación/hash/ciclo) que se elige en función de dos factores principales, 1) índices en las columnas unidas 2) estadísticas que predicen el tamaño de la unión Por lo tanto, cada vez que ejecuta la consulta, según el tamaño estimado de la combinación, elige la combinación adecuada. ¿La selección de combinación se ha convertido en una consulta compilada? Es decir. Si el rastreo de parámetros predice mal el tamaño típico de las uniones, ¿introducirá en el plan de consulta el tipo de unión mal elegido? – AaronLS

24

Una forma simple de acelerar eso es reasignar los parámetros de entrada a los parámetros locales en el mismo comienzo del sproc, p.

CREATE PROCEDURE uspParameterSniffingAvoidance 
    @SniffedFormalParameter int 
AS 
BEGIN 

    DECLARE @SniffAvoidingLocalParameter int 
    SET @SniffAvoidingLocalParameter = @SniffedFormalParameter 

    --Work w/ @SniffAvoidingLocalParameter in sproc body 
    -- ... 
+1

Esta solución redujo el tiempo de ejecución de mi consulta del 50%. No es perfecto, pero mejor! –

+0

Pero, ¿por qué eso ayuda de todos modos? –

+1

@ TimBüthe: Funciona evitando que SQL Server almacene en caché (o utilizando una versión en caché de) un plan de consulta para su procedimiento. Dependiendo del valor de su parámetro, un plan de ejecución de consulta puede ser más rápido o más lento que otro. La primera vez que se ejecuta el procedimiento, se generará un plan basado en el valor de ese primer parámetro. Al reasignarlo localmente, SQL Server usará un nuevo plan cada vez. –

4

El rastreo de parámetros es una técnica que SQL Server utiliza para optimizar el plan de ejecución de consultas para un procedimiento almacenado. Cuando llama por primera vez al procedimiento almacenado, SQL Server examina los valores de los parámetros proporcionados de su llamada y decide qué índices usar en función de los valores de los parámetros.

De modo que cuando la primera llamada contiene parámetros no muy típicos, SQL Server puede seleccionar y almacenar un plan de ejecución subóptimo con respecto a las siguientes llamadas del procedimiento almacenado.

Puede solucionar esto ya sea

  • usando WITH RECOMPILE
  • copiar los valores de los parámetros a variables locales dentro del procedimiento almacenado y el uso de los locales en sus consultas.

Incluso escuché que es mejor no usar procedimientos almacenados sino enviar sus consultas directamente al servidor. Recientemente me encontré con el mismo problema donde aún no tengo una solución real. Para algunas consultas, la copia a los vars locales ayuda a volver al plan de ejecución correcto, para algunas consultas el rendimiento se degrada con los vars locales.

Todavía tengo que investigar más sobre cómo SQL Server almacena en caché y reutiliza (subóptimo) los planes de ejecución.

4

En mi experiencia, la mejor solución para el olfato de parámetros es 'Dynamic SQL'. Dos cosas importantes a tener en cuenta es que 1. debe usar parámetros en su consulta dinámica sql 2. debe usar sp_executesql (y no sp_execute), que guarda el plan de ejecución para cada valor de parámetro

+0

En un mundo de SQL Inyección de ataques, no creo que recomendar SQL dinámico sea una buena idea. – datagod

+1

También recomendó el uso de parámetros, que es cómo puede evitar la inyección de SQL. –

-2

Cambiar el procedimiento de la tienda para ejecutar como un lote debe aumentar la velocidad.

seleccionar archivos por lotes es decir .:

exec ('select * from order where order id ='''+ @ordersID') 

En lugar del procedimiento almacenado normal, seleccione:

select * from order where order id = @ordersID 

sólo tiene que pasar en el parámetro como nvarchar y usted debe obtener resultados más rápidos.

0

Tuve un problema similar. El plan de ejecución de mi procedimiento almacenado tomó 30-40 segundos. Intenté usar las Declaraciones de SP en la ventana de consulta y me llevó unos pocos ms ejecutarlas. Luego resolví declarando las variables locales dentro del procedimiento almacenado y transfiriendo los valores de los parámetros a las variables locales. Esto hizo que la ejecución de SP fuera muy rápida y ahora el mismo SP se ejecuta en pocos milisegundos en lugar de 30-40 segundos.

-1

Muy simple y ordenado, el optimizador de consultas utiliza un plan de consulta antiguo para consultas que se ejecutan con frecuencia. pero en realidad el tamaño de los datos también está aumentando, por lo que en ese momento se requiere un nuevo plan optimizado y un optimizador de consultas utilizando el plan de consulta antiguo. Esto se llama Detección de parámetros. También he creado publicaciones detalladas sobre esto. Por favor visite esta url: http://www.dbrnd.com/2015/05/sql-server-parameter-sniffing/

Cuestiones relacionadas