Najlepsza metoda na wdrożenie filtrowanego wyszukiwania

17

Chciałbym Cię zapytać o Twoją opinię, jeśli chodzi o wdrożenie filtrowanego formularza wyszukiwania. Wyobraźmy sobie następujący przypadek:

  • 1 Duży stół z dużą ilością kolumn
  • Ważne może być powiedzenie, że ten SQL Server

Musisz zaimplementować formularz do przeszukiwania danych w tej tabeli, aw tym formularzu będziesz mieć kilka pól wyboru, które pozwolą Ci zminimalizować to wyszukiwanie.

Teraz moje pytanie brzmi, który z poniższych powinien być najlepszym sposobem na wdrożenie wyszukiwania?

  1. Utwórz procedurę składowaną z zapytaniem w środku. Ta procedura składowana sprawdzi, czy parametry są podane przez aplikację, aw przypadku, gdy nie zostaną one podane, w kwerendzie zostanie wstawiony znak zastępczy.

  2. Utwórz zapytanie dynamiczne, które jest budowane zgodnie z danymi podanymi przez aplikację.

Pytam o to, ponieważ wiem, że SQL Server tworzy plan wykonania po utworzeniu procedury przechowywanej, aby zoptymalizować jej wydajność, ale czy tworząc dynamiczne zapytanie wewnątrz procedury przechowywanej, poświęcimy optymalizację uzyskaną przez plan wykonania?

Proszę, powiedz mi, jakie byłoby najlepsze podejście w twoim przekonaniu.

j0N45
źródło
Stwierdzasz poniżej, że zmierzasz w kierunku rozwiązania dynamicznego. To fajnie, pamiętaj tylko o wyliczeniu możliwych filtrów i wsparciu ich indeksów. Dopóki zapytania są budowane konsekwentnie, powinny być wydajne.
Matthew Flynn

Odpowiedzi:

10

Możesz przyjrzeć się odpowiedzi na to podobne pytanie tutaj: /programming/11329823/add-where-clauses-to-sql-dynamically-programmatically

Odkryliśmy, że SPROC, który przyjmuje kilka opcjonalnych parametrów i implementuje taki filtr:

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)

zbuforuje pierwszy plan wykonania, z którym jest uruchamiany (np. @optionalParam1 = 'Hello World', @optionalParam2 = NULL), ale następnie wykona nieszczęśliwie, jeśli przekażemy mu inny zestaw parametrów opcjonalnych (np @optionalParam1 = NULL, @optionalParam2 = 42.). (I oczywiście zależy nam na wydajności planu buforowanego, więc nie WITH RECOMPILEma go)

Wyjątkiem jest tutaj to, że jeśli w zapytaniu jest co najmniej jeden filtr OBOWIĄZKOWY, który jest WYSOCE selektywny i odpowiednio zindeksowany, oprócz parametrów opcjonalnych, to powyższy PROC będzie działał dobrze.

Jednakże, jeśli WSZYSTKIE filtry są opcjonalne, dość okropną prawdą jest to, że sparametryzowany dynamiczny sql faktycznie działa lepiej (chyba że napiszesz N! Różne statyczne PROCS dla każdej permutacji parametrów opcjonalnych).

Dynamiczny SQL, taki jak poniżej, utworzy i buforuje inny plan dla każdej permutacji parametrów zapytania, ale przynajmniej każdy plan będzie „dostosowany” do konkretnego zapytania (nie ma znaczenia, czy jest to PROC, czy Adhoc SQL - ponieważ dopóki są sparametryzowane, będą buforowane)

Stąd moja preferencja dla:

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

itp. Nie ma znaczenia, czy przekażemy nadmiarowe parametry do sp_executesql - są one ignorowane. Warto zauważyć, że ORM, takie jak Linq2SQL i EF, używają sparametryzowanego dynamicznego sql w podobny sposób.

StuartLC
źródło
1
Tak, tak myślałem, to była opcja, którą wybrałem. Chciałem tylko upewnić się, że był dobry. Dziękuję za odpowiedź.
j0N45
„Jeśli instrukcja SQL jest wykonywana bez parametrów, SQL Server wewnętrznie parametryzuje instrukcję, aby zwiększyć możliwość dopasowania jej do istniejącego planu wykonania. Proces ten nazywa się prostą parametryzacją.” Więc w zasadzie program może użyć czegoś takiego jak „gdzie numer_pliku =” + nazwa pliku. Oczywiście to otwiera puszki robaków, ale to inny temat ;-)
Codism
5

Zacznij od tego, co uważasz za łatwiejsze do wdrożenia (tak sądzę, opcja 2). Następnie zmierz wydajność rzeczywistych danych. Optymalizację można rozpocząć tylko w razie potrzeby, a nie wcześniej.

Nawiasem mówiąc, w zależności od stopnia złożoności filtrów wyszukiwania, zadanie może nie zostać łatwo rozwiązane bez dynamicznego SQL. Nawet jeśli korzystasz z procedury składowanej, najprawdopodobniej nie zwiększy to wydajności, jak już podejrzewasz. Z drugiej strony, jeśli to pomaga, istnieje kilka rodzajów wskazówek (patrz http://www.simple-talk.com/sql/performance/controlling-execution-plans-with-hints/ ), które można dodać do kodu SQL kwerenda, dynamiczna lub nie, aby pomóc serwerowi SQL zoptymalizować plan wykonania.

Doktor Brown
źródło
Cóż, wdrożyłem już opcję 2 i myślę, że to najlepszy sposób, głównie dlatego, że symbole wieloznaczne drastycznie obniżą wydajność, jednak poświęcam konserwację, ponieważ zwiększy to złożoność kodu. Chciałem tylko wiedzieć, czy ktoś zna lepszą opcję dla takich sytuacji.
j0N45
Oddałbym ci głos, ale przepraszam, nie mam reputacji.
j0N45