Beste Methode zur Implementierung einer gefilterten Suche

17

Ich möchte Sie nach Ihrer Meinung fragen, wenn es um die Implementierung eines gefilterten Suchformulars geht. Stellen wir uns folgenden Fall vor:

  • 1 großer Tisch mit vielen Spalten
  • Es könnte wichtig sein zu sagen, dass dieser SQL Server

Sie müssen ein Formular implementieren, um Daten in dieser Tabelle zu suchen. In diesem Formular sind mehrere Kontrollkästchen vorhanden, mit denen Sie diese Suche anpassen können.

Nun meine Frage hier ist, welche der folgenden Möglichkeiten am besten geeignet ist, um die Suche zu implementieren?

  1. Erstellen Sie eine gespeicherte Prozedur mit einer darin enthaltenen Abfrage. Diese gespeicherte Prozedur prüft, ob die Parameter von der Anwendung angegeben wurden. Wenn sie nicht angegeben werden, wird ein Platzhalter in die Abfrage eingefügt.

  2. Erstellen Sie eine dynamische Abfrage, die entsprechend den Angaben der Anwendung erstellt wird.

Ich frage dies, weil ich weiß, dass SQL Server beim Erstellen der gespeicherten Prozedur einen Ausführungsplan erstellt, um die Leistung zu optimieren. Werden wir jedoch durch das Erstellen einer dynamischen Abfrage innerhalb der gespeicherten Prozedur die durch den Ausführungsplan erzielte Optimierung opfern?

Bitte sagen Sie mir, was für Sie der beste Ansatz wäre.

j0N45
quelle
Sie geben unten an, dass Sie zur dynamischen Lösung tendieren. Das ist cool, stellen Sie einfach sicher, dass Sie die möglichen Filter auflisten und Indizes haben, die sie unterstützen. Solange die Abfragen konsistent erstellt werden, sollten sie effizient sein.
Matthew Flynn

Antworten:

10

Vielleicht möchten Sie die Antwort auf diese ähnliche Frage hier suchen: /programming/11329823/add-where-clauses-to-sql-dynamically-programmatically

Wir haben festgestellt, dass ein SPROC eine Reihe von optionalen Parametern aufnimmt und den Filter folgendermaßen implementiert:

CREATE PROC MyProc (@optionalParam1 NVARCHAR(50)=NULL, @optionalParam2 INT=NULL)
AS 
...
SELECT field1, field2, ... FROM [Table]
WHERE 
  (@optionalParam1 IS NULL OR MyColumn1 = @optionalParam1)
  AND (@optionalParam2 IS NULL OR MyColumn2 = @optionalParam2)

Zwischenspeichern des ersten Ausführungsplans, mit dem er ausgeführt wird (z. B. @optionalParam1 = 'Hello World', @optionalParam2 = NULL), dann jedoch miserabel, wenn ein anderer Satz optionaler Parameter übergeben wird (z @optionalParam1 = NULL, @optionalParam2 = 42. B. ). (Und natürlich wollen wir die Leistung des zwischengespeicherten Plans, also WITH RECOMPILEist es aus)

Die Ausnahme hier ist, dass, wenn AUCH mindestens ein OBLIGATORISCHER Filter in der Abfrage vorhanden ist, der HOCH selektiv und ordnungsgemäß indiziert ist, zusätzlich zu den optionalen Parametern, der obige PROC eine gute Leistung erbringt.

Wenn jedoch ALLE Filter optional sind, ist die Wahrheit ziemlich schrecklich, dass parametrisiertes dynamisches SQL tatsächlich eine bessere Leistung erbringt (es sei denn, Sie schreiben N! Unterschiedliche statische PROCS für jede Permutation optionaler Parameter).

Dynamisches SQL wie das folgende erstellt und speichert für jede Permutation der Abfrageparameter einen anderen Plan im Cache, aber mindestens jeder Plan wird auf die spezifische Abfrage zugeschnitten (es spielt keine Rolle, ob es sich um ein PROC - oder ein Ad - hoc - SQL handelt) solange es sich um parametrisierte Abfragen handelt, werden sie zwischengespeichert)

Daher meine Präferenz für:

DECLARE @SQL NVARCHAR(MAX)        

-- Mandatory / Static part of the Query here
SET @SQL = N'SELECT * FROM [table] WHERE 1 = 1'

IF @OptionalParam1 IS NOT NULL        
    BEGIN        
        SET @SQL = @SQL + N' AND MyColumn1 = @optionalParam1'    
    END        

IF @OptionalParam2 IS NOT NULL        
    BEGIN        
        SET @SQL = @SQL + N' AND MyColumn2 = @optionalParam2'    
    END        

EXEC sp_executesql @SQL,        
    N'@optionalParam1 NVARCHAR(50), 
      @optionalParam2 INT'
    ,@optionalParam1 = @optionalParam1
    ,@optionalParam2 = @optionalParam2

usw. Es spielt keine Rolle, ob wir redundante Parameter an sp_executesql übergeben - sie werden ignoriert. Es ist erwähnenswert, dass ORMs wie Linq2SQL und EF in ähnlicher Weise parametrisiertes dynamisches SQL verwenden.

StuartLC
quelle
1
Ja, ich dachte schon, das war die Option, die ich gewählt habe. Ich wollte nur sicherstellen, dass es gut war. Danke für die Antwort.
j0N45
"Wenn eine SQL-Anweisung ohne Parameter ausgeführt wird, parametrisiert SQL Server die Anweisung intern, um die Möglichkeit des Abgleichs mit einem vorhandenen Ausführungsplan zu erhöhen. Dieser Vorgang wird als einfache Parametrisierung bezeichnet." Grundsätzlich kann das Programm also etwas wie "where filenumber =" + filename verwenden. Das öffnet natürlich eine Dose Würmer, aber das ist ein anderes Thema ;-)
Codism
5

Beginnen Sie mit dem, was Ihrer Meinung nach einfacher zu implementieren ist (ich denke, Option 2). Dann messen Sie die Leistung für reale Daten. Beginnen Sie erst bei Bedarf mit der Optimierung, nicht vorher.

Je nachdem, wie komplex Ihre Suchfilter sind, kann Ihre Aufgabe übrigens ohne dynamisches SQL möglicherweise nicht einfach gelöst werden. Selbst wenn Sie eine gespeicherte Prozedur verwenden, wird dies die Leistung wahrscheinlich nicht erhöhen, wie Sie bereits vermutet haben. Auf der anderen Seite gibt es verschiedene Arten von Hinweisen (siehe http://www.simple-talk.com/sql/performance/controlling-execution-plans-with-hints/ ), die Sie zu einer SQL hinzufügen können Abfrage, dynamisch oder nicht, um SQL Server bei der Optimierung seines Ausführungsplans zu unterstützen.

Doc Brown
quelle
Nun, ich habe Option 2 bereits implementiert, und ich denke, dies ist der beste Weg, vor allem, weil Wildcards die Leistung drastisch verringern, aber ich opfere die Wartung, da dies die Komplexität des Codes erhöht. Ich wollte nur wissen, ob jemand eine bessere Option für diese Art von Situationen kennt.
j0N45
Ich würde Sie abstimmen lassen, aber es tut mir leid, dass ich keinen Ruf habe.
j0N45