2013-01-08 17 views
14

Mam kwerendę sql poniżej, że działa bardzo wolno. Przyjrzałem się planowi wykonania i twierdzę, że sortowanie w Files.OrderId jest operacją o najwyższym koszcie (53%). Dlaczego miałoby to mieć miejsce, gdyby nigdzie nie zamawiałem przez OrderId? Czy najlepiej jest utworzyć indeks na File.OrderId?Dlaczego w moim planie wykonawczym występuje sortowanie?

Execution plan jeśli ktoś jest zainteresowany.

with custOrders as 
(
    SELECT c.firstName + ' ' + c.lastname as Customer, c.PartnerId , c.CustomerId,o.OrderId,o.CreateDate, c.IsPrimary 
    FROM Customers c 
    LEFT JOIN CustomerRelationships as cr 
     ON c.CustomerId = cr.PrimaryCustomerId 
    INNER JOIN Orders as o 
     ON c.customerid = o.customerid 
      OR (cr.secondarycustomerid IS NOT NULL AND o.customerid = cr.secondarycustomerid) 
    where c.createdate >= @FromDate + ' 00:00' 
     AND c.createdate <= @ToDate + ' 23:59' 
), 
temp as 
(
SELECT Row_number() 
     OVER ( 
      ORDER BY c.createdate DESC)     AS 'row_number', 
     c.customerid as customerId, 
     c.partnerid as partnerId, 
     c.Customer, 
     c.orderid as OrderId, 
     c.createdate as CreateDate, 
     Count(f.orderid)         AS FileCount, 
     dbo.Getparentcustomerid(c.isprimary, c.customerid) AS ParentCustomerId, 
     au.firstname + ' ' + au.lastname     AS Admin, 
     '' as blank, 
     0 as zero 
FROM custOrders c 
     INNER JOIN files f 
       ON c.orderid = f.orderid 
     INNER JOIN admincustomers ac 
       ON c.customerid = ac.customerid 
     INNER JOIN adminusers au 
       ON ac.adminuserid = au.id 
     INNER JOIN filestatuses s 
       ON f.statusid = s.statusid 
WHERE ac.adminuserid IS NOT NULL 
     AND f.statusid NOT IN (5, 6) 
GROUP BY c.customerid, 
      c.partnerid, 
      c.Customer, 
      c.isprimary, 
      c.orderid, 
      c.createdate, 
      au.firstname, 
      au.lastname 
) 
+0

* Błąd podczas sprawdzania źródłowego XML * – Kermit

+0

Tak widziałem to. Czy to naprawdę robi różnicę? Nadal możesz zobaczyć kod XML ... –

+0

Czy "POWYŻEJ" nie oznacza sortowania? – Kermit

Odpowiedz

11

Serwer SQL ma trzy algorytmy do wyboru, gdy musi połączyć dwie tabele. The Nested-Loops-Join, the Hash-Join i the Sort-Merge-Join. Który wybierze, opiera się na kosztorysach. W tym przypadku doszło do wniosku, że na podstawie informacji, które posiadał, właściwym wyborem było "Sort-Merge-Join".

W planach wykonania programu SQL Server Sort-Merge jest dzielony na dwa operatory, Sortowanie i scalanie, ponieważ operacja sortowania może nie być konieczna, na przykład, jeśli dane są już posortowane.

Dla mor informacji o dołącza sprawdzić moje dołączyć szereg tutaj: http://sqlity.net/en/1146/a-join-a-day-introduction/ artykułu o Sort-Merg-Join jest tutaj: http://sqlity.net/en/1480/a-join-a-day-the-sort-merge-join/


Aby zapytanie szybciej, po raz pierwszy będzie wyglądać w indeksach . W zapytaniu znajduje się klaster sklasyfikowanych skanów indeksu. Jeśli możesz wymienić kilka z nich w poszukiwaniu, najprawdopodobniej będziesz lepszy. Sprawdź także, czy oszacowania, które produkuje SQL Server, odpowiadają faktycznej liczbie wierszy w rzeczywistym planie wykonania. Jeśli są daleko, SQL Server często dokonuje złych wyborów. Zapewnienie lepszych statystyk może również pomóc w sprawdzaniu wydajności.

+0

+1 dla rzeczywistej liczby wierszy i statystyk –

1

myślę rodzaj występuje za to dołączyć:

FROM custOrders c 
     INNER JOIN files f 
       ON c.orderid = f.orderid 

Chciałbym utworzyć indeks plików, który zawiera kolumny idZamówienia i StatusId od kwerenda używa również kolumnę StatusId.

Można też rozważyć następujące zmiany:

  1. Nie potrzeba "ac.adminuserid IS NOT NULL" jak to jest objęte wewnętrzna przyłączyć między adminusers i admincustomers
  2. Zmień test "f.statusid NOT IN (5, 6)" na stan pozytywny (np. In), ponieważ warunki ujemne są droższe w przetwarzaniu.
+0

[pliki] ma już indeks obejmujący –

+0

Tak, już robi indeksowanie w nie klastrowanych indeksach na 'Files'. Czy istnieje sposób na dalszą redukcję liczby rekordów pochodzących z 'Files'? –

+0

Poszukiwanie indeksowe nie klastrowane jest dobrze z punktu widzenia wydajności. Drugą zmianą w celu zmniejszenia liczby rekordów jest wyeliminowanie sprawdzania NOT IN względem stanuid jak zalecałem powyżej. –

2

SQL Server wykonuje sortowanie, aby umożliwić połączenie scalania między zestawem danych po prawej stronie operatora sortowania i rekordami w tabeli Orders. Łączenie się samo w sobie jest bardzo wydajnym sposobem łączenia wszystkich rekordów w zestawie danych, ale wymaga, aby każdy zestaw danych, który ma zostać dołączony, był sortowany zgodnie z kluczami łączenia w tej samej kolejności.

Ponieważ klucz PK_Orders jest już zamówiony przez OrderID, SQL Server zdecydował się go wykorzystać, sortując drugi koniec sprzężenia (pozostałe elementy po prawej stronie sortowania), aby dwa zestawy danych mogły zostać scalone w tym momencie planu. Typową alternatywą łączenia łączeń jest łączenie skrótów, ale to nie pomogłoby, ponieważ zamiast tego zamiast sortowania i scalania zamiast niego byłby kosztowny operator łączenia wartości mieszania. Optymalizator zapytań określił sortowanie i scalanie, aby było bardziej wydajne w tym przypadku.

Podstawową przyczyną kosztownego kroku w planie jest potrzeba połączenia wszystkich rekordów z tabeli zamówień do zbioru danych. Czy istnieje sposób ograniczenia zapisów pochodzących ze stołu files? Indeks na files.statusid może być przydatny, jeśli rekordy nie w 5,6 są mniejsze niż 10% całkowitego rozmiaru tabeli.

QO uważa, że ​​większość rekordów zostanie odfiltrowana na końcu. Spróbuj przenieść tak wiele warunków filtrowania z powrotem do źródeł rekordów, aby mniej zapisów musiało być obsłużonych w połowie planu.

EDYCJA: Zapomniałem wspomnieć, bardzo pomocne jest posiadanie planu wykonania, na który możemy patrzeć. Czy jest jakiś sposób, aby uzyskać plan wykonania rzeczywisty, aby zobaczyć rzeczywistą liczbę rekordów przechodzących przez te operatory? Czasami szacowana liczba rekordów może być trochę za mała.

EDIT: Patrząc głębiej w 2 do pola bazowego ostatni podmiot filtracyjnej, podsumowana:

c.CustomerId=o.CustomerId 
OR o.CustomerId=cr.SecondaryCustomerId AND cr.SecondaryCustomerId IS NOT NULL 

wygląda SQL Server produkuje krzyż dołączyć pomiędzy wszystkie możliwe rekordy pasujące między Orders i Customers do tej wskaż zapytanie (plan po prawej od drugiego do ostatniego operatora filtru), a następnie przejrzyj każdy rekord z tym warunkiem, aby sprawdzić, czy rzeczywiście pasuje. Zauważ, że linia przechodząca przez filtr jest naprawdę gruba, a linia wychodząca jest naprawdę cienka? Dzieje się tak, ponieważ szacowany rząd wierszy przechodzi od 21k do 4 po tym operatorze. Zapomnij o tym, co powiedziałem wcześniej, to prawdopodobnie główny problem w planie. Nawet jeśli istnieją indeksy na tych kolumnach, SQL Server nie może ich użyć, ponieważ warunek łączenia jest zbyt skomplikowany. To powoduje, że plan scala wszystkie rekordy, zamiast szukać tylko tych, których potrzebujesz, ponieważ nie może od razu użyć pełnego predykatu łączenia.

Moja pierwsza myśl jest przeformułowanie CTE custOrders jako związek dwóch zestawów danych: jeden przy użyciu CustomerId i jeden za pomocą SecondaryCustomerId się przyłączyć. Powoduje to duplikowanie pracy reszty CTE, ale jeśli pozwala na właściwe użycie indeksów, może to być duża wygrana.

+0

OK, zaktualizowałem z aktualnym planem –

+0

Nadal wygląda jak pierwotny szacowany plan. Czy edytowałeś pytanie lub zmieniałeś dokument na XML Playground? –

0

Wiem, że to pytanie jest dość stare, jednak miałem ten sam problem i zdałem sobie sprawę, że był zupełnie inny powód, dlaczego moje stoły nagle zwolniły. Objawy były takie same, powolne aktualizowanie widoków, które wcześniej były błyskawicznie szybkie. "Sortuj", podając koszt 40%. To rozwiązanie może okazać się przydatne dla użytkownika i jest proste. Podczas dołączania do tabel upewnij się, że dołączasz do bazy "na podobnej zasadzie". Dołączyłem do dwóch tabel na identyfikatorze. Jednak w jednej tabeli mój identyfikator został ustawiony jako int, a drugi jako nvarchar. Poprawiłem to, aby oba były zdefiniowane jako ten sam typ, a widok powrócił do prędkości błyskawicy.

Mam nadzieję, że pomoże to komuś innemu uniknąć spędzenia tygodnia próbując dowiedzieć się, co jest nie tak z SQL, kiedy jest to naprawdę moment PEBKAC.

(Problem istnieje między klawiaturą i krzesło)

Powiązane problemy