2012-05-18 14 views
6

Necesito usar la misma consulta dos veces pero tengo una cláusula where ligeramente diferente. Me preguntaba si sería eficiente simplemente llamar al mismo proceso almacenado con un valor de bit, y tener una declaración IF ... ELSE ..., decidiendo qué campos comparar.¿Cómo compila Sql Server los planes de ejecución para el flujo lógico en los procedimientos almacenados?

¿O debería hacer dos procs almacenados y llamar a cada uno según la lógica en mi aplicación?

Me gustaría saber esto más detalladamente para entenderlo correctamente. ¿Cómo se compila el plan de ejecución para esto? ¿Hay uno para cada bloque de código en cada IF ... ELSE ...?

¿O se compila como un gran plan de ejecución?

+0

¿cuál sería el 'SI ... ELSE .. .' (o 'CASE') ¿contienen exactamente? En algunos casos, es posible y más eficiente abstraer el condicional en parámetros. Usted tiene un plan de ejecución por proceso, por lo que la lógica condicional puede dar como resultado un rendimiento desigual. –

Respuesta

1

Se compila una vez utilizando el valor inicial de los parámetros pasados ​​al procedimiento. Aunque algunas declaraciones pueden estar sujetas a compilación diferida, en ese caso se compilarán con los valores de los parámetros que se compilen.

Puede ver esto al ejecutar el siguiente y mirar los planes de ejecución reales.

CREATE TABLE T 
    (
    C INT 
) 

INSERT INTO T 
SELECT 1 AS C 
UNION ALL 
SELECT TOP (1000) 2 
FROM master..spt_values 
UNION ALL 
SELECT TOP (1000) 3 
FROM master..spt_values 

GO 

CREATE PROC P @C INT 
AS 
    IF @C = 1 
     BEGIN 
      SELECT '1' 
      FROM T 
      WHERE C = @C 
     END 
    ELSE IF @C = 2 
     BEGIN 
      SELECT '2' 
      FROM T 
      WHERE C = @C 
     END 
    ELSE IF @C = 3 
     BEGIN 
      CREATE TABLE #T 
      (
       X INT 
      ) 

      INSERT INTO #T 
      VALUES  (1) 

      SELECT '3' 
      FROM T, 
       #T 
      WHERE C = @C 
     END 

GO 

EXEC P 1 

EXEC P 2 

EXEC P 3 

DROP PROC P 

DROP TABLE T 

Correr el caso 2 muestra un número estimado de filas procedentes de T como 1 no 1000 porque esa declaración fue hecha de acuerdo al valor del parámetro inicial aprobada en de 1. Al ejecutar el caso 3, se obtiene un recuento estimado exacto de 1000, ya que la referencia a la tabla temporal (que aún no se ha creado) significa que la sentencia estuvo sujeta a una compilación diferida.

3

Tiene razón en estar preocupado por el plan de ejecución que se está almacenando en caché.

Martin ofrece un buen ejemplo que muestra que el plan está en caché y se optimizará para una cierta rama de su lógica la primera vez que se ejecuta. Después de la primera ejecución, ese plan se reutiliza incluso si llama al procedimiento almacenado (sproc) con un parámetro diferente que hace que su flujo de ejecución elija otra rama. Esto es muy malo y matará el rendimiento. He visto esto suceder muchas veces y lleva un tiempo encontrar la causa raíz.

La razón detrás de esto se llama "Parameter Sniffing" y vale la pena investigar.

Una solución común propuesta (una que yo no aconsejo) es dividir su sproc en unos pequeños. Si llama a un sproc dentro de un sproc ese sproc interno obtendrá un plan de ejecución optimizado para el parámetro que se le pasa.

Dividir un sproc en unos pocos más pequeños cuando no hay un buen motivo (una buena razón sería la modularidad) es una solución fea. Martin muestra que es posible recompilar una declaración introduciendo un cambio en el esquema. Usaría OPCIÓN (RECOMPULE) al final de la declaración. Esto le indica al optimizador que realice una recopilación de instrucciones teniendo en cuenta el valor actual de variables: no solo se tienen en cuenta los parámetros, sino también las variables locales que pueden marcar la diferencia entre un plan bueno y uno malo.

Para volver a su pregunta de construir una consulta con una cláusula where diferente según un parámetro.Me gustaría utilizar el siguiente patrón:

WHERE 
(@parameter1 is null or col1 = @parameter1 ) 
AND 
(@parameter2 is null or col2 = @parameter2 ) 
... 
OPTION (RECOMPILE) 

El lado negativo es que el plan de ejecución de esta declaración no se almacena en caché (no influye en el almacenamiento en caché hasta el punto de la declaración sin embargo) que puede tener un impacto si el sproc se ejecuta muchas veces ya que ahora se debe tener en cuenta el tiempo de compilación. Realizar una prueba con datos de calidad de producción le dará la respuesta si es un problema o no.

Lo bueno es que puede codificar sprocs legibles y legibles y no configurar el optimizador con el pie equivocado.

Otra opción a tener en cuenta es que puede deshabilitar el almacenamiento en caché del plan de ejecución en el nivel sproc (a diferencia del nivel de declaración) que es menos granular y, más importante aún, no tendrá en cuenta el valor de las variables locales al optimizar

Más información en http://www.sommarskog.se/dyn-search-2005.html http://sqlinthewild.co.za/index.php/2009/03/19/catch-all-queries/

+0

¿Por qué no votar? Una respuesta legítima. –

Cuestiones relacionadas