/ Zapytanie / MSSQL działa wolno z dużą ilością LEFT JOIN - sql-server, left-join

Zapytanie MSSQL działa wolno z wieloma LEWYMI DOŁĄCZAMI - sql-server, left-join

Pracuję z serwerem mssql 2008r2.Mam ogromne tabele, które zawierają 19 sklepów danych o obrotach dzień po dniu pozycja po pozycji. Ma około 100 milionów wierszy. Ale w widoku podzielonym na partycje łatwo jest uruchamiać zapytania.

Struktura tabeli wygląda następująco:

  1. Nazwa sklepu
  2. Identyfikator przedmiotu
  3. Data
  4. Obrót handlowy
  5. Sprzedana ilość

Raport wyjściowy wygląda następująco: Identyfikator towaru, data, magazyn_1.obrót, magazyn_1.quantity, sklep_2.obrót, magazyn_2.ilość ....

Aby stworzyć tego rodzaju raport, używam tego zapytania:

WITH cte_sell AS(
SELECT *
FROM view_turnover
WHERE date BETWEEN "130413" and "130418" )

SELECT a.item_id,a.date,
store_1.turnover,store_1.quantity,
store_2.turnover,store_2.quantity,
store_3.turnover,store_3.quantity

FROM (SELECT DISTINCT item_id,date FROM cte_sell) as a
LEFT JOIN (SELECT * FROM cte_sell WHERE store="Store 1") as Store_1 ON a.item_id=store_1.item_id and a.date=store_1.date
LEFT JOIN (SELECT * FROM cte_sell WHERE store="Store 2") as Store_2 ON a.item_id=store_2.item_id and a.date=store_2.date
LEFT JOIN (SELECT * FROM cte_sell WHERE store="Store 3") as Store_3 ON a.item_id=store_3.item_id and a.date=store_3.date

Mam nadzieję, że rozumiesz zapytanie.

Zapytanie działa mniej niż 10 sekund przez 14-15store (14 15 LEFT JOIN), co jest dobre. Ale problem polega na tym, że gdy wybieram wszystkie 19 magazynu (19 LEFT JOIN), zapytanie dramatycznie zwalnia. Zakończenie może zająć 2 lub 3 minuty.

Tworzenie planu wykonania również trwa znacznie dłużej:

  • Przez 12 przechowuj tylko 2 sekundy
  • Przez 19 przechowywać 22 sekundy

Jak myślisz, czy są jakieś ograniczenia w dołączaniu do stołów? Myślę, że jest jakiś parametr serwera, który kontroluje ogromne zapytania. Czy ktoś ma pomysł, jak zoptymalizować zapytanie lub serwer?

Najgorsze jest to, że serwer czasami się zawiesza:Utworzyłem plik śledzenia, gdy zapytanie było uruchamiane o godzinie 9:00 i 12:00. O godzinie 9 wykonanie zapytania zajęło 2 minuty. O 12 musiałem ponownie uruchomić comupetr po 10 minutach, ponieważ nie mogę ponownie uruchomić usługi SQL z menedżera konfiguracji.

Nie mogę dołączyć screnshotów.

W monitorze aktywności proces jest zawieszony. Typ oczekiwania to: CXPACKET Zasób oczekiwania to: exchange ... Przepraszam, ale nie wiem zbyt wiele o zamkach.

Próbowałem połączyć się ze studia zarządzania iOtrzymuję ten komunikat: Pomyślnie nawiązano połączenie z serwerem, ale podczas procesu logowania wystąpił błąd. (Dostawca: Dostawca TCP, błąd: 0 (Przetłumacz z węgierskiego): Istniejące połączenie zostało zmuszone do zamknięcia przez zdalną maszynę.

Odpowiedzi:

1 dla odpowiedzi № 1

Czy rozważałeś usunięcie podzapytań i użycie po prostu warunków łączenia?

WITH cte_sell AS(
SELECT *
FROM view_turnover
WHERE date BETWEEN "130413" and "130418" )

SELECT a.item_id,a.date,
store_1.turnover,store_1.quantity,
store_2.turnover,store_2.quantity,
store_3.turnover,store_3.quantity

FROM (SELECT DISTINCT item_id,date FROM cte_sell) as a
LEFT JOIN cte_sell as Store_1 ON a.item_id=store_1.item_id and a.date=store_1.date and Store="Store 1"
LEFT JOIN cte_sell as Store_2 ON a.item_id=store_2.item_id and a.date=store_2.date and store="Store 2"
LEFT JOIN cte_sell as Store_3 ON a.item_id=store_3.item_id and a.date=store_3.date and store="Store 3"

0 dla odpowiedzi nr 2

Uważam, że problem polega na tym, że SQL Server tego nie robiwydają się optymalizować wyrażenia CTE, gdy pojawiają się one wielokrotnie w zapytaniu. Innymi słowy, jeśli spojrzysz na plan wykonania, widok jest wykonywany trzy razy - dla każdego magazynu wzmianek.

Czy możesz mieć każdy sklep w różnych rzędach? Jeśli tak, spróbuj tego:

WITH cte_sell AS (
SELECT *
FROM view_turnover
WHERE date BETWEEN "130413" and "130418"
)
SELECT a.item_id, a.date, store, turnover, quantity
FROM (SELECT DISTINCT item_id,date FROM cte_sell) as a left join
cte_sell cs
on a.item_id=cs.item_id and a.date=cs.date and cs.store in ("Store 1", "Store 2", "Store 3")

Jeśli potrzebujesz jednego wiersza z wieloma sklepami, to agregacja warunkowa lub pivot rozwiąże problem.

Jeśli chcesz zobaczyć wszystkie wartości w jednym wierszu, użyj agregacji warunkowej w powyższym zapytaniu:

WITH cte_sell AS (
SELECT *
FROM view_turnover
WHERE date BETWEEN "130413" and "130418"
)
SELECT a.item_id, a.date,
max(case when store = "Store 1" then turnover end),
max(case when store = "Store 1" then quantity end),
max(case when store = "Store 2" then turnover end),
max(case when store = "Store 2" then quantity end),
max(case when store = "Store 3" then turnover end),
max(case when store = "Store 3" then quantity end)
FROM (SELECT DISTINCT item_id,date FROM cte_sell) as a left join
cte_sell cs
on a.item_id=cs.item_id and a.date=cs.date and cs.store in ("Store 1", "Store 2", "Store 3")
group by a.item_id, a.date