TL; DR
Ponieważ to pytanie wciąż się wyświetla, podsumuję je tutaj, aby nowi przybysze nie musieli cierpieć historii:
JOIN table t ON t.member = @value1 OR t.member = @value2 -- this is slow as hell
JOIN table t ON t.member = COALESCE(@value1, @value2) -- this is blazing fast
-- Note that here if @value1 has a value, @value2 is NULL, and vice versa
Zdaję sobie sprawę, że to nie może być problem każdego, ale podkreślenie wrażliwości klauzul ON może pomóc ci spojrzeć we właściwym kierunku. W każdym razie oryginalny tekst jest dostępny dla przyszłych antropologów:
Oryginalny tekst
Rozważ następujące proste zapytanie (tylko 3 tabele)
SELECT
l.sku_id AS ProductId,
l.is_primary AS IsPrimary,
v1.category_name AS Category1,
v2.category_name AS Category2,
v3.category_name AS Category3,
v4.category_name AS Category4,
v5.category_name AS Category5
FROM category c4
JOIN category_voc v4 ON v4.category_id = c4.category_id and v4.language_code = 'en'
JOIN category c3 ON c3.category_id = c4.parent_category_id
JOIN category_voc v3 ON v3.category_id = c3.category_id and v3.language_code = 'en'
JOIN category c2 ON c2.category_id = c3.category_id
JOIN category_voc v2 ON v2.category_id = c2.category_id and v2.language_code = 'en'
JOIN category c1 ON c1.category_id = c2.parent_category_id
JOIN category_voc v1 ON v1.category_id = c1.category_id and v1.language_code = 'en'
LEFT OUTER JOIN category c5 ON c5.parent_category_id = c4.category_id
LEFT OUTER JOIN category_voc v5 ON v5.category_id = c5.category_id and v5.language_code = @lang
JOIN category_link l on l.sku_id IN (SELECT value FROM #Ids) AND
(
l.category_id = c4.category_id OR
l.category_id = c5.category_id
)
WHERE c4.[level] = 4 AND c4.version_id = 5
Jest to dość proste zapytanie, jedyną mylącą częścią jest ostatnie połączenie kategorii, jest tak, ponieważ poziom kategorii 5 może, ale nie musi istnieć. Na końcu zapytania szukam informacji o kategorii według identyfikatora produktu (SKU ID) i tam właśnie pojawia się bardzo duża tabela link_ kategorii. Wreszcie tabela #Ids jest tylko tabelą tymczasową zawierającą 10 000 ID.
Po wykonaniu otrzymuję następujący rzeczywisty plan wykonania:
Jak widać, prawie 90% czasu spędza się w zagnieżdżonych pętlach (sprzężenie wewnętrzne). Oto dodatkowe informacje na temat tych zagnieżdżonych pętli:
Zauważ, że nazwy tabel nie pasują dokładnie, ponieważ zredagowałem nazwy tabel zapytań dla czytelności, ale dość łatwo można je dopasować (ads_alt_category = kategoria). Czy istnieje sposób zoptymalizowania tego zapytania? Zauważ też, że w produkcji tabela temp. #Ids nie istnieje, jest to parametr wyceniony w tabeli o tych samych 10 000 ID przekazanych do procedury składowanej.
Dodatkowe informacje:
- indeksy kategorii na id_kategorii i id_kategorii nadrzędnej
- index_voc category_id, kod_języka
- indeks_kategorii na sku_id, id_kategorii
Edytuj (rozwiązany)
Jak wskazano w zaakceptowanej odpowiedzi, problemem była klauzula OR w JOIN category_link. Jednak kod sugerowany w zaakceptowanej odpowiedzi jest bardzo wolny, wolniejszy nawet niż kod oryginalny. O wiele szybszym i czystszym rozwiązaniem jest po prostu zastąpienie obecnego warunku JOIN następującym:
JOIN category_link l on l.sku_id IN (SELECT value FROM @p1) AND l.category_id = COALESCE(c5.category_id, c4.category_id)
Ta drobna poprawka jest najszybszym rozwiązaniem, przetestowanym pod kątem podwójnego łączenia z zaakceptowanej odpowiedzi, a także przetestowanym pod kątem ZASTOSOWANIA KRZYŻOWEGO, jak sugeruje valverij.