Różnica między UNION ALL i UNION w SQL Server
Operacje na zbiorach danych
Spośród wielu różnych operacji na zbiorach w SQL Server można wyróżnić jedną, która jest często błędnie stosowana. O ile operatory różnicy zbiorów (EXCEPT) oraz części wspólnej, czyli przecięcia (INTERSECT) nie stwarzają problemów, o tyle jest pewna drobna rzecz, o której należy pamiętać korzystając z operatora sumy. Operator sumy (UNION) występuje w dwóch wersjach. Doświadczenie pokazuje, że dla wielu osób jest to pewnego rodzaju niespodzianka. Rzadko bowiem ktoś zanurza się w dokumentacje tak głęboko, żeby doczytać o pełnej sumie zbiorów, czyli instrukcji UNION ALL. Skoro UNION działa, to nie ma potrzeby szukać czegoś innego.
Jaka jest różnica?
Różnica jest oczywista i sprowadza się do innego traktowania elementów powtarzających się. Słowo kluczowe UNION napotykając na powtarzające się elementy zadba o to, aby w wyniku pojawiło się tylko jedno wystąpienie. UNION ALL działa inaczej. Jeżeli dany element się powtarza, wtedy w wyniku znajdzie się dwa razy. Przyjrzyjmy się prostemu skryptowi zaprezentowanemu poniżej aby przekonać się, jak to wszystko działa.
(
Nazwa nvarchar(32)
)
CREATE TABLE TechnologieNet
(
Nazwa nvarchar(32)
)
INSERT INTO Technologie VALUES
('WCF'),
('AJAX'),
('Silverlight')
INSERT INTO TechnologieNet VALUES
('.NET Remoting'),
('ASP.NET'),
('Silverlight')
SELECT * FROM Technologie
UNION
SELECT * FROM TechnologieNet
SELECT * FROM Technologie
UNION ALL
SELECT * FROM TechnologieNet
Przyjrzyjmy się teraz różnicom w wynikach. Pierwsze zapytanie zwróci taki oto wynik:
Nazwa |
.NET Remoting |
AJAX |
ASP.NET |
Silverlight |
WCF |
A teraz tabela druga:
Nazwa |
WCF |
AJAX |
Silverlight |
.NET Remoting |
ASP.NET |
Silverlight |
Oprócz wspomnianego usunięcia duplikatów stała się jeszcze jedna rzecz: rekordy ułożone są w innej kolejności. Sugeruje to, że całe wyrażenie wyliczane jest nieco inaczej i rzeczywiście tak jest. Przyjrzyjmy się planom wykonania powyższych instrukcji SELECT.
Plany wykonania UNION i UNION ALL
Różnica uwidacznia się także na planie wykonania. Plan wykonania dla instrukcji UNION będzie wyglądał następująco:
Rys. 1. Plan wykonania instrukcji UNION.
Plan wykonania instrukcji UNION ALL jest nieco inny. Wyraźnie widać, że pominięta została operacja sortowania. Trzeba wiedzieć, że operacja sortowania jest jedną z najbardziej kosztownych operacji na zbiorze danych, dotkliwie dającą się we znaki zwłaszcza wtedy, gdy tych danych jest bardzo dużo. Plan wykonania UNION ALL pokazany jest na poniższej ilustracji:
Rys. 1. Plan wykonania instrukcji UNION ALL.
DISTINCT + UNION ALL = UNION
Prosta zależność przedstawiona w tytule sekcji nie jest przypadkowa. Zaprezentowane równanie, tak prawdę mówiąc, opisuje sposób wykonywania instrukcji UNION przez SQL Server. Łatwo się o tym przekonać wykonując zaprezentowany poniżej skrypt i oglądając wygenerowany dla tej instrukcji plan wykonania - jest dokładnie taki sam jak dla wyrażenia UNION.
SELECT * FROM Technologie
UNION ALL
SELECT * FROM TechnologieNet) SQ
Sprawdzenie planu wykonania pozostawiam czytelnikom.
Konsekwencje wydajnościowe operacji sortowania
Dwa różne sposoby wyliczania zbiorów wynikowych przez SQL Server powinny skłonić czytelnika do zadania sobie ważnego pytania: co z wydajnością? Z jednej strony UNION zwraca tych wyników mniej, z drugiej zaś, zwracane wyniki są posortowane. Jak już wspomniałem, znacznie bardziej kosztowną operacją jest sortowanie. Dość kosztowne są też same odczyty z dysku twardego. Same operacje wstawienia na koniec zbioru wynikowego realizowane są już w pamięci operacyjnej komputera będącego serwerem bazy danych, które są o kilka rzędów wielkości szybsze niż operacje na pamięci masowej. Sam optymalizator, wskazując procentowy rozkład czasów wykonania tych dwóch instrukcji (UNION i UNION ALL), daje 73% czasu dla UNION i 27 dla UNION ALL. Trzeba wiedzieć, że rozbieżności zwiększają się wraz ze zwiększaniem się zbiorów, które muszą być sortowane. Unikajmy zatem sortowania, jeżeli jest to tylko możliwe.
Wnioski
Postaram się na koniec podkreślić to, na co powinniśmy zwrócić uwagę podczas wyboru UNION lub UNION ALL. Po pierwsze, jeżeli mamy pewność, że rekordy w dwóch zbiorach nie będą się powtarzać lub nie zależy nam na unikalności zbioru wynikowego - bezwzględnie stosujmy UNION ALL. Różnice w czasie wykonywania się zapytań mogą być ogromne. Jeżeli unikatowość musi być zapewniona, a w dwóch zbiorach elementy się powtarzają - wtedy nie mamy innego wyjścia.
Kategoria:SQL Server
Komentarze: