2014-11-13 7 views
9

ich häufig gespeicherte Prozeduren mit Code wie folgt finden:Leistungsüberlegungen für Conditional Abfragen (Search Forms)

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 + '%') 
… 

Ist das besser als so etwas wie dieses:

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

und es ist egal, ob Ich ziehe die Ausdrücke, die nur von Parametern

dann verwenden Sie @Param3Search anstelle von @Param3?

Entschuldigung, etwas so weites zu fragen, aber ich bin sicher, dass es einige allgemeine Faustregeln für das Schreiben solcher Fragen gibt. Ich konnte dazu keine bestehende Frage finden.

+2

[Catch-all-Abfragen] (http://sqlinthewild.co.za/index.php/2009/03/19/catch-all-queries/) ist eine hervorragende Ressource für diese Frage. – DMason

Antwort

4

Die endgültigen Artikel zu diesem Thema werden von Dynamic Search Conditions in T-SQL

Ihre Frage ist 2008. Wenn Sie auf mindestens SP1 SQL Server markiert verknüpft CU5 sind, dann können Sie die Vorteile der „Parameter Embedding Optimierung“ Verhalten als Alternative nehmen zu dynamischem SQL.

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); 

Wird bei jedem Aufruf neu kompiliert werden und in der Lage sein, unter Berücksichtigung der Ist-Größe/Parameterwerte für die Ausführung zu übernehmen.

Angenommen, für den Moment sind alle NOT NULL. Der Plan wird für

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

kompiliert werden (ich würde wahrscheinlich sehen, ob das Prädikat Erweiterung heraus Column3 besser Pläne zu LED)

Nehmen wir nun an, dass sie alle NULL sind.Der Plan sollte

SELECT columns 
FROM table_source 

Dies kann besser verwaltbar als der dynamische SQL-Ansatz vereinfachen und bedeutet weniger möglicherweise einzelne Nutzungspläne im Cache aber den zusätzlichen Aufwand von Neuübersetzung hat.

2

Ich verwende normalerweise Dynamic SQL für diesen Zweck.

So etwas .....

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 

Das Problem mit anderem Ansatz (@Param2 IS NULL OR Column2 = @Param2) ist SQL Server ist nicht kurzschluß Abfragen wie folgt. Selbst wenn der Parameter null ist, kann er trotzdem weiterlaufen und versucht, die Ausdrücke Column2 = @ Param2 auszuwerten.

Daher verwenden Sie dynamic sql Sie bauen Ihre Abfragen abhängig von den Variablen und führen dann die Abfrage nur mit erforderlichen where-Klauseln.

Wenn Sie Dynamic sql innerhalb Ihrer gespeicherten Prozeduren verwenden, haben Sie die Möglichkeit parametrisierte Ausführungspläne für eine gespeicherte Prozedur.

Mit Ihrem aktuellen Ansatz Parameter Sniffing wird die Leistung aus einer sehr einfachen Abfrage saugen.

Moral der Geschichte: Stick auf dynamische SQL mit dieser Art von optionalen Parametern und verwenden Sie sp_executesql System gespeicherte Prozedur (schützt Sie gegen SQL-Injektion Angriffe), bessere Leistung und weniger harte Arbeit für Ihren SQL-Server.