2010-03-05 15 views
6

Mam tabelę ItemValue pełen danych na SQL 2005 Server uruchomiony w 2000 trybie zgodności, który wygląda mniej więcej tak (to zdefiniowana przez użytkownika wartości tabela):Optymalizacja SQL - zmiany planu wykonania na podstawie wartości wiązania - Dlaczego?

ID ItemCode  FieldID Value 
-- ---------- ------- ------ 
1 abc123    1 D 
2 abc123    2 287.23 
4 xyz789    1 A 
5 xyz789    2 3782.23 
6 xyz789    3 23 
7 mno456    1 W 
9 mno456    3 45 
           ... and so on. 

FieldID pochodzi z ItemField tabela:

ID FieldNumber DataFormatID Description ... 
-- ----------- ------------ ----------- 
1    1    1 Weight class 
2    2    4 Cost 
3    3    3 Another made up description 
.    .    x xxx 
.    .    x xxx 
.    .    x xxx 
x    91 (we have 91 user-defined fields) 

Ponieważ nie mogę PIVOT w trybie 2000, utknęliśmy budowy brzydkie zapytanie korzystając przypadkach i GROUP bY, aby uzyskać dane wyglądać jak powinien dla s ome aplikacje Legacy, który brzmi:

ItemNumber Field1 Field2 Field3 .... Field51 
---------- ------ ------- ------ 
    abc123 D  287.23 NULL 
    xyz789 A  3782.23 23 
    mno456 W  NULL  45 

Widać musimy tylko tę tabelę, aby pokazać wartości do 51. UDF. Oto zapytanie:

SELECT 
    iv.ItemNumber, 
    ,MAX(CASE WHEN f.FieldNumber = 1 THEN iv.[Value] ELSE NULL END) [Field1] 
    ,MAX(CASE WHEN f.FieldNumber = 2 THEN iv.[Value] ELSE NULL END) [Field2] 
    ,MAX(CASE WHEN f.FieldNumber = 3 THEN iv.[Value] ELSE NULL END) [Field3] 
     ... 
    ,MAX(CASE WHEN f.FieldNumber = 51 THEN iv.[Value] ELSE NULL END) [Field51] 
FROM ItemField f 
LEFT JOIN ItemValue iv ON f.ID = iv.FieldID 
WHERE f.FieldNumber <= 51 
GROUP BY iv.ItemNumber 

Gdy FieldNumber ograniczeniem jest < = 51, wykonanie planu idzie mniej więcej tak:

SELECT <== Computer Scalar <== Stream Aggregate <== Sort (Cost: 70%) <== Hash Match <== (Clustered Index Seek && Table Scan)

i to szybko! Mogę cofnąć ponad 100 000 rekordów w ciągu sekundy, co odpowiada naszym potrzebom.

Jednak gdybyśmy mieli więcej UDF i zmienić ograniczenie do niczego powyżej (tak, testowałem je jeden po drugim) lub usunąć je całkowicie, tracę sortowane w plan wykonania, a to zostaje zastąpiony całą masą bloków równoległościowości, które zbierają, dzielą i rozprowadzają strumienie, a cała sprawa jest powolna (30 sekund nawet na 1 rekord).

FieldNumber ma klastrowych niepowtarzalny indeks i jest częścią kompozytu podstawowego klucza z ID kolumnowej (wskaźnik nieklastrowanym) w ItemField tabeli. W ItemValue stołu ID i Nummer artykułu kolumny dokonać PK, a tam jest dodatkowy nieklastrowanym indeks na kolumnieNummer artykułu.

Jaki jest tego powód? Dlaczego zmiana mojego prostego ograniczenia liczby całkowitej zmienia cały plan wykonania?

A jeśli już chcesz ... co zrobiłbyś inaczej? Za kilka miesięcy planowane jest uaktualnienie SQL, ale wcześniej muszę rozwiązać ten problem.

+0

Co zrobiłbym inaczej, nie używaj tej struktury tabeli. Znacznie lepiej jest użyć struktury z określonymi polami dla 99% potrzebnych danych, które można z góry określić, niż użyć tabeli EAV. Nawiasem mówiąc, tryb zgodności nie uniemożliwia korzystania z nowych funkcji, jest umożliwienie korzystania z funkcji, które nie są już dozwolone. Jeśli jednak tworzysz bazę danych z bazą danych 2000 z 2000 roku, najlepiej jest unikać nowych funkcji. – HLGEM

Odpowiedz

4

SQL Server jest wystarczająco inteligentny, aby uwzględnić ograniczenia CHECK podczas optymalizacji zapytań.

Twój f.FieldNumber <= 51 jest zoptymalizowany, a optymalizator widzi, że należy połączyć dwie tabele (najlepiej z HASH JOIN).

Jeśli nie masz ograniczenia, silnik musi sprawdzić warunek i najprawdopodobniej używa do tego celu indeksowania. To może być wolniejsze.

Proszę o przesłanie wszystkich planów dotyczących zapytań? Po prostu uruchom SET SHOWPLAN_TEXT ON, a następnie zapytania.

Aktualizacja:

Jakie jest uzasadnienie tego? Dlaczego zmiana mojego prostego ograniczenia liczby całkowitej zmienia cały plan wykonania?

Jeśli przez ograniczenie rozumiesz warunek WHERE, jest to prawdopodobnie druga rzecz.

Operacje na ustawieniach (tak robi SQL) nie mają jednego najbardziej wydajnego algorytmu: wydajność każdego algorytmu zależy w dużym stopniu od rozkładu danych w zestawach.

Załóżmy, że do pobrania podzestawu (tak robi klauzula WHERE) można znaleźć zakres rekordu w indeksie i użyć wskaźników rekordu indeksu do zlokalizowania wierszy danych w tabeli lub po prostu zeskanować wszystkie rekordy w tabeli i filtruj je przy użyciu warunku WHERE.

Wydajność poprzedniego działania jest m × const, że tego ostatniego jest n gdzie m jest numer dowodu spełnienia warunku, n to całkowita liczba wpisów w tabeli oraz const > 1.

Oznacza to, że w przypadku większych wartości m funkcja pełnego skanowania jest bardziej wydajna.

jest tego świadomy i zmienia plany wykonania zgodnie ze stałymi, które mają wpływ na dystrybucję danych w operacjach zestawu.

ABY to zrobić, SQL Server utrzymuje statystyki: zagregowane histogramy rozkładu danych w każdej indeksowanej kolumnie i wykorzystuje je do tworzenia planów zapytań.

Tak więc zmiana liczby całkowitej w warstwie WHERE w rzeczywistości wpływa na rozmiar i rozkład danych podstawowych zestawów i sprawia, że ​​SQL Server ponownie rozważa algorytmy najlepiej pasujące do pracy z zestawami tego rozmiaru i układu.

+0

Nie widzę żadnej wzmianki o ograniczeniu CHECK w OP ... –

+0

Będę publikować plany, ale muszę wprowadzić kilka zmian, więc moje prawdziwe tabele nie dają żadnych informacji identyfikujących (mój przykład jest naprawiony). –

+0

@Remus: Kiedy go przeczytałem, wierzyłem, że * gdy ograniczenie FieldNumber wynosi '<= 51' * było o ograniczeniu' CHECK', ale prawdopodobnie masz rację, @p wiele znaczyło stan "WHERE". – Quassnoi

0

robi zastąpić całą masę bloków równoległość

Spróbuj tego:

SELECT 
    iv.ItemNumber, 
    ,MAX(CASE WHEN f.FieldNumber = 1 THEN iv.[Value] ELSE NULL END) [Field1] 
    ,MAX(CASE WHEN f.FieldNumber = 2 THEN iv.[Value] ELSE NULL END) [Field2] 
    ,MAX(CASE WHEN f.FieldNumber = 3 THEN iv.[Value] ELSE NULL END) [Field3] 
     ... 
    ,MAX(CASE WHEN f.FieldNumber = 51 THEN iv.[Value] ELSE NULL END) [Field51] 
FROM ItemField f 
LEFT JOIN ItemValue iv ON f.ID = iv.FieldID 
WHERE f.FieldNumber <= 51 
GROUP BY iv.ItemNumber 
OPTION (Maxdop 1) 

Korzystając Option (MAXDOP 1), powinno to zapobiec parellelism w planie wykonania.

+0

To faktycznie działa, ale nie można umieścić opcji w widoku, ponieważ jest to potrzebne. –

0

W wieku 66 lat uderzasz w pewien wewnętrzny próg kosztów szacunkowych, który decyduje, że lepiej jest użyć jednego planu względem drugiego. To, czym jest ten próg i dlaczego tak się dzieje, nie jest tak naprawdę ważne. Zauważ, że twoje zapytanie różni się od każdej wartości FieldNumber, ponieważ nie tylko zmieniasz WHERE: zmieniasz również wyświetlane pseudo-'pivot 'pola.

Teraz nie wiem, wszystkie szczegóły swojego stolika i zapytań i włożyć/aktualizacji/usuwania/wzór, ale dla danego zapytania, które pisał właściwą strukturę indeksu klastrowego dla tabeli ItemValue to:

CREATE CLUSTERED INDEX [cdxItemValue] ON ItemValue (FieldID, ItemNumber); 

Ta struktura eliminuje potrzebę pośredniego sortowania wyników dla tego zapytania "pivot".

Powiązane problemy