2013-03-15 11 views
5

Dlaczego ta kwerenda szybciej w SQL Server 2008 R2 (wersja 10.50.2806.0)Zapytanie szybciej z górnym atrybutem

SELECT 
     MAX(AtDate1), 
     MIN(AtDate2) 
    FROM 
    (
     SELECT TOP 1000000000000 
      at.Date1 AS AtDate1, 
      at.Date2 AS AtDate2 
     FROM 
      dbo.tab1 a 
     INNER JOIN 
      dbo.tab2 at 
     ON 
      a.id = at.RootId 
     AND CAST(GETDATE() AS DATE) BETWEEN at.Date1 AND at.Date2 
     WHERE 
      a.Number = 223889 
    )B 

następnie

SELECT 
     MAX(AtDate1), 
     MIN(AtDate2) 
    FROM 
    (
     SELECT 
      at.Date1 AS AtDate1, 
      at.Date2 AS AtDate2 
     FROM 
      dbo.tab1 a 
     INNER JOIN 
      dbo.tab2 at 
     ON 
      a.id = at.RootId 
     AND CAST(GETDATE() AS DATE) BETWEEN at.Date1 AND at.Date2 
     WHERE 
      a.Number = 223889 
    )B 

?

Druga instrukcja z atrybutem TOP jest sześciokrotnie szybsza.

Wewnętrzne podzapytanie count(*) ma 9280 wierszy.

Czy mogę użyć polecenia WSTAW, aby zadeklarować, że optymalizator programu SQL Server jest odpowiedni? execution plan

+0

Będziesz musiał sprawdzić plan wykonania, aby się upewnić. Jest prawdopodobne, że zajmuje bardziej wydajną ścieżkę z TOP niż bez. – Khan

+2

Może to być spowodowane problemem z optymalizatorem. Czy możesz podać plany wykonania dla obu zapytań? –

+3

Najlepszym sposobem na dostarczenie planów wykonania jest uruchomienie ich w SSMS z włączoną opcją "Query -> Include Actual Execution", a następnie przesłanie wersji XML na stronę taką jak pastebin. Zobacz [Jak udostępnić plan wykonania komuś do analizy?] (Http://meta.dba.stackexchange.com/questions/796/how-do-i-provide-an-execution-plan-to-someone- do analizy) po więcej. –

Odpowiedz

3

Widzę, że opublikowałeś teraz the plans. Tylko szczęście losowania.

Twoje zapytanie dotyczy 16 dołączeń do tabeli.

SELECT max(atDate1) AS AtDate1, 
     min(atDate2) AS AtDate2, 
     max(vtDate1) AS vtDate1, 
     min(vtDate2) AS vtDate2, 
     max(bgtDate1) AS bgtDate1, 
     min(bgtDate2) AS bgtDate2, 
     max(lftDate1) AS lftDate1, 
     min(lftDate2) AS lftDate2, 
     max(lgtDate1) AS lgtDate1, 
     min(lgtDate2) AS lgtDate2, 
     max(bltDate1) AS bltDate1, 
     min(bltDate2) AS bltDate2 
FROM (SELECT TOP 100000 at.Date1 AS atDate1, 
          at.Date2 AS atDate2, 
          vt.Date1 AS vtDate1, 
          vt.Date2 AS vtDate2, 
          bgt.Date1 AS bgtDate1, 
          bgt.Date2 AS bgtDate2, 
          lft.Date1 AS lftDate1, 
          lft.Date2 AS lftDate2, 
          lgt.Date1 AS lgtDate1, 
          lgt.Date2 AS lgtDate2, 
          blt.Date1 AS bltDate1, 
          blt.Date2 AS bltDate2 
     FROM dbo.Tab1 a 
       INNER JOIN dbo.Tab2 at 
       ON a.id = at.Tab1Id 
        AND cast(Getdate() AS DATE) BETWEEN at.Date1 AND at.Date2 
       INNER JOIN dbo.Tab5 v 
       ON v.Tab1Id = a.Id 
       INNER JOIN dbo.Tab16 g 
       ON g.Tab5Id = v.Id 
       INNER JOIN dbo.Tab3 vt 
       ON v.id = vt.Tab5Id 
        AND cast(Getdate() AS DATE) BETWEEN vt.Date1 AND vt.Date2 
       LEFT OUTER JOIN dbo.Tab4 vk 
       ON v.id = vk.Tab5Id 
       LEFT OUTER JOIN dbo.VerkaufsTab3 vkt 
       ON vk.id = vkt.Tab4Id 
       LEFT OUTER JOIN dbo.Plu p 
       ON p.Tab4Id = vk.Id 
       LEFT OUTER JOIN dbo.Tab15 bg 
       ON bg.Tab5Id = v.Id 
       LEFT OUTER JOIN dbo.Tab7 bgt 
       ON bgt.Tab15Id = bg.Id 
        AND cast(Getdate() AS DATE) BETWEEN bgt.Date1 AND bgt.Date2 
       LEFT OUTER JOIN dbo.Tab11 b 
       ON b.Tab15Id = bg.Id 
       LEFT OUTER JOIN dbo.Tab14 lf 
       ON lf.Id = b.Id 
       LEFT OUTER JOIN dbo.Tab8 lft 
       ON lft.Tab14Id = lf.Id 
        AND cast(Getdate() AS DATE) BETWEEN lft.Date1 AND lft.Date2 
       LEFT OUTER JOIN dbo.Tab13 lg 
       ON lg.Id = b.Id 
       LEFT OUTER JOIN dbo.Tab9 lgt 
       ON lgt.Tab13Id = lg.Id 
        AND cast(Getdate() AS DATE) BETWEEN lgt.Date1 AND lgt.Date2 
       LEFT OUTER JOIN dbo.Tab10 bl 
       ON bl.Tab11Id = b.Id 
       LEFT OUTER JOIN dbo.Tab6 blt 
       ON blt.Tab10Id = bl.Id 
        AND cast(Getdate() AS DATE) BETWEEN blt.Date1 AND blt.Date2 
     WHERE a.Nummer = 223889) B 

zarówno na dobrych i złych planów plan wykonania pokazuje „Reason wcześniejszego rozwiązania Oświadczenie Optimization” AS „Time Out”.

Dwa plany mają nieco inne zamówienia łączenia.

Jedynym łączeniem w planach, które nie spełniają kryteria wyszukiwania indeksu, jest Tab9. Ma 63.926 wierszy.

Brakujące szczegóły indeksu w planie wykonania sugerują utworzenie następującego indeksu.

CREATE NONCLUSTERED INDEX [miising_index] 
ON [dbo].[Tab9] ([Date1],[Date2]) 
INCLUDE ([Tab13Id]) 

Problematyczny częścią złej planie widać wyraźnie w SQL Sentry Plan Explorer

Bad Plan

SQL Server szacuje, że 1.349174 wiersze zostaną zwrócone z poprzedniego łączy przyjście do łączenia na Tab9. I dlatego koszty zagnieżdżonych pętli łączą się tak, jakby trzeba było wykonać skanowanie na wewnętrznej tabeli 1.349174 razy.

W rzeczywistości do tego połączenia podłącza się 2600 wierszy, co oznacza, że ​​wykonuje 2 600 pełnych skanów Tab9 (2600 * 63,926 = 164,569,600 wierszy.)

Tak się składa, że ​​na dobrym planie szacowana liczba rzędów wchodzących do łączenia to 2,74319. Jest to nadal błędne o trzy rzędy wielkości, ale nieznacznie zwiększone oszacowanie oznacza, że ​​SQL Server faworyzuje zamiast tego sprzężenie hash. Hash dołączyć właśnie robi jednorazowym przejściu przez Tab9

Good Plan

chciałbym najpierw spróbować dodać brakujące indeksu Tab9.

także/zamiast można spróbować aktualizacji statystyki dotyczące wszystkich tabel zaangażowanych (zwłaszcza tych z datą orzecznika takich jak Tab2Tab3Tab7Tab8Tab6) i sprawdzić, czy to w pewien sposób korygowania ogromną różnicę między szacowanymi a rzeczywistymi rzędach na lewa część planu.

Pomocne może być również podzielenie zapytania na mniejsze części i zmaterializowanie ich na tymczasowe tabele z odpowiednimi indeksami. SQL Server może następnie użyć statystyk dotyczących tych częściowych wyników, aby podejmować lepsze decyzje dotyczące późniejszych połączeń w ramach planu.

Tylko w ostateczności mogę rozważyć użycie wskazówek dotyczących zapytań, aby spróbować wymusić plan przy użyciu sprzężenia hash. Dostępne opcje to albo podpowiedź USE PLAN, w którym to przypadku dyktujesz dokładnie plan, który chcesz, łącznie z wszystkimi typami złączeń i zamówieniami, albo podając LEFT OUTER HASH JOIN tab9 .... Ta druga opcja ma również skutek uboczny polegający na naprawianiu wszystkich zamówień łączenia w planie. Oba oznaczają, że SQL Server będzie poważnie ograniczony, to jego zdolność do dostosowania planu ze zmianami w dystrybucji danych.

1

Trudno odpowiedzieć, nie znając rozmiaru i struktury stołów i nie mogąc zobaczyć całego planu wykonania. Ale różnica w obu planach to dopasowanie Hash Match do zapytania "top n" a połączenie Nested Loop do drugiego. Hash Match jest bardzo intensywnym połączeniem z zasobami, ponieważ serwer musi przygotować hash bucket, aby go użyć. Ale staje się znacznie bardziej efektywny w przypadku dużych tabel, natomiast zagnieżdżone pętle, porównując każdy wiersz w jednej tabeli z każdym wierszem w innej tabeli, doskonale sprawdzają się w przypadku małych tabel, ponieważ nie ma takiego przygotowania. Co myślę, że wybierając TOP 1000000000000 wierszy w podzapytanie dajesz optymalizatorowi wskazówkę, że podzapytasz wygeneruje ogromną ilość danych, więc używa dopasowania Hash. Ale w rzeczywistości wynik jest niewielki, więc zagnieżdżone pętle działają lepiej. To, co właśnie powiedziałem, oparte jest na strzępach informacji, więc proszę, serce krytykuj moją odpowiedź;).

+0

to jest plan wykonania zapytań http://www.dateiupload.net/download.php?file = 0875b65fb14d01c90b48c5fd146a36e3 – JJANSSEN

+0

dzięki za odpowiedź. jak mogę dać optymalizatorowi podpowiedź do używania sprzężenia hash, więc mogę usunąć najwyższy atrybut – JJANSSEN

Powiązane problemy