2014-11-13 10 views
9

Mi capita spesso di trovare stored procedure con codice come questo:Considerazioni sulle prestazioni per condizionali query di ricerca (forme)

SELECT columns 
FROM table_source 
WHERE 
    (@Param1 IS NULL OR Column1 LIKE @Param1) 
AND (@Param2 IS NULL OR Column2 = @Param2) 
AND (@Param3 IS NULL OR ISNULL(Column3,'') LIKE @Param3 + '%') 
… 

E` meglio di qualcosa di simile:

WHERE 
    (Column1 LIKE COALESCE(@Param1, Column1)) 
AND (Column2 = COALESCE(@Param2, Column2)) 
AND (ISNULL(Column3,'') LIKE COALESCE(@Param3 + '%', ISNULL(Column3, ''))) 
… 

e cosa importa se Estraggo le espressioni che dipendono solo dai parametri

DECLARE @Param3Search nvarchar(30); 
SET @Param3Search = @Param3 + '%'; 

quindi utilizzare @Param3Search anziché @Param3?

Siamo spiacenti di chiedere una cosa così ampia, ma sono sicuro che ci sono alcune regole generali per scrivere tali query. Non sono riuscito a trovare una domanda esistente su questo.

+2

[catch-all query] (http://sqlinthewild.co.za/index.php/2009/03/19/catch-all-queries/) è una risorsa eccellente per questo domanda. – DMason

risposta

4

Gli articoli definitivi su questo argomento sono legati da Dynamic Search Conditions in T-SQL

la tua domanda è etichettato SQL Server 2008. Se si è su almeno CU5 SP1 allora si può approfittare del comportamento "Parametro Embedding Optimization" come alternativa a SQL dinamico.

SELECT columns 
FROM table_source 
WHERE (@Param1 IS NULL 
      OR Column1 LIKE @Param1) 
     AND (@Param2 IS NULL 
       OR Column2 = @Param2) 
     AND (@Param3 IS NULL 
       OR ISNULL(Column3, '') LIKE @Param3 + '%') 
OPTION (RECOMPILE); 

Sarà ricompilato su ogni chiamata e sarà in grado di tenere conto dei valori attuali della variabile/parametro per quella esecuzione.

Assumiamo per il momento che tutti sono NOT NULL. Il piano sarà compilata per

SELECT columns 
FROM table_source 
WHERE Column1 LIKE @Param1 
     AND Column2 = @Param2 
     AND ISNULL(Column3, '') LIKE @Param3 + '%' 

(probabilmente sarei guardo per vedere se espansione fuori il predicato sulla Colonna3 ha portato a migliori piani di troppo)

Ora supporre che essi sono tutti NULL.Il piano dovrebbe semplificare al

SELECT columns 
FROM table_source 

Questo può essere più gestibile rispetto all'approccio SQL dinamico e mezzi meno piani regolatori eventualmente singoli nella cache ma ha l'overhead aggiuntivo di ricompilazione.

2

Normalmente utilizzo Dynamic SQL A tale scopo.

Qualcosa di simile .....

DECLARE @Param1 [DataType] 
DECLARE @Param2 [DataType] 
DECLARE @Param3 [DataType] 

DECLARE @SQL NVARCHAR(MAX); 


SET @SQL = N'SELECT columns FROM table_source WHERE 1 = 1 ' 
      + CASE WHEN @Param1 IS NOT NULL 
       THEN N' AND Column1 LIKE @Param1 '  ELSE N' ' END 
      + CASE WHEN @Param2 IS NOT NULL 
       THEN N' AND Column2 = @Param2 '   ELSE N' ' END 
      + CASE WHEN @Param3 IS NOT NULL 
       THEN N' AND Column3 LIKE @Param3 +''%'' ' ELSE N' ' END 

EXECUTE sp_executesql @SQL 
        ,N'@Param1 DataType, @Param2 DataType, @Param3 DataType' 
        ,@Param1 
        ,@Param2 
        ,@Param3 

Il problema con altro approccio (@Param2 IS NULL OR Column2 = @Param2) è SQL Server non query corto circuito come questo. Anche se il parametro è nullo, potrebbe comunque andare avanti e provare a valutare le espressioni Column2 = @ Param2.

Pertanto, utilizzando SQL dinamico si costruiscono le query in base alle variabili e quindi si esegue la query solo con le clausole where necessarie.

Anche l'utilizzo di SQL dinamico all'interno delle stored procedure consente di avere piani di esecuzione parametrizzati per una stored procedure.

Con il tuo approccio attuale, lo sniffing dei parametri aspira le prestazioni da una query molto semplice.

Morale della storia: attenersi a SQL dinamico con questo tipo di parametri facoltativi e utilizzare sp_executesql stored procedure di sistema (protegge da attacchi SQL injection), prestazioni migliori e meno hardwork per il server sql.

Problemi correlati