Miałem ten problem dawno temu, znalazłem obejście, które mi pasowało i zapomniałem o tym.
Ale teraz jest takie pytanie na SO, więc jestem skłonny poruszyć ten problem.
Istnieje widok, który łączy kilka tabel w bardzo prosty sposób (zamówienia + wiersze zamówień).
Zapytanie bez where
klauzuli powoduje zwrócenie kilku milionów wierszy.
Jednak nikt nigdy tak go nie nazywa. Zwykle jest to zapytanie
select * from that_nasty_view where order_number = 123456;
Zwraca około 10 rekordów z 5m.
Ważna rzecz: widok zawiera funkcję okna rank()
, która jest dokładnie podzielona na pola, za pomocą których widok jest zawsze odpytywany:
rank() over (partition by order_number order by detail_line_number)
Teraz, jeśli ten widok jest zapytany o dosłowne parametry w ciągu zapytania, dokładnie tak jak pokazano powyżej, natychmiast zwraca wiersze. Plan wykonania jest w porządku:
- Szukaj indeksu w obu tabelach przy użyciu indeksów
order_number
(zwraca 10 wierszy). - Obliczanie okien nad zwróconym drobnym wynikiem.
- Wybieranie
Jednak gdy widok jest wywoływany w sparametryzowany sposób, robi się nieprzyjemnie:
Index scan
we wszystkich tabelach ignorując indeksy. Zwraca 5m wierszy.- Ogromne dołączenie.
- Obliczanie okien dla wszystkich
partition
s (około 500k okien). Filter
wziąć 10 rzędów z 5 m.- Wybierz
Dzieje się tak we wszystkich przypadkach, gdy zaangażowane są parametry. Może to być SSMS:
declare @order_number int = 123456;
select * from that_nasty_view where order_number = @order_number;
Może to być klient ODBC, taki jak Excel:
select * from that_nasty_view where order_number = ?
Lub może to być dowolny inny klient, który używa parametrów, a nie konkatenacji SQL.
Jeśli funkcja okna zostanie usunięta z widoku, działa idealnie szybko, niezależnie od tego, czy jest pytana o parametry, czy nie.
Moim obejściem było usunięcie funkcji obrażającej i ponowne zastosowanie jej na późniejszym etapie.
Ale co daje? Czy to naprawdę błąd w działaniu funkcji okna przez SQL Server 2008?
order_number
nie jest kluczem podstawowym. Jestint not null
w nim indeks nieklastrowany w obu tabelach.OPTION (RECOMPILE)
pomocy?Odpowiedzi:
Wydaje się, że jest to długotrwały problem, który utrzymuje się na nowo w takiej czy innej formie i nadal występuje w SQL Server 2012.
Niektóre posty na ten temat są
Wszystkie bieżące wersje programu SQL Server do 2012 roku włącznie nie są w stanie wypchnąć filtra w grupie partycjonowania poza projekt sekwencji dla sparametryzowanego predykatu, chyba że
option(recompile)
jest używany (jeśli 2008+).Alternatywą dla
recompile
podpowiedzi byłoby przepisanie zapytania w celu użycia sparametryzowanego wbudowanego TVF, zgodnie z sugestią @ a1ex07)źródło
Spróbowałbym zastąpić widok udf o wartości tabeli. W ten sposób najpierw filtruje rekordy, a następnie stosuje funkcję okna. Ta funkcja może akceptować parametr tabeli, dzięki czemu można przekazać
order_number
do niego wiele parametrówźródło
SELECT * FROM my_funct(12345)
it will filter records first, and then apply window function
jest nieprawidłowe. Nie ma deterministycznego nakazu egzekucji