Spis treści:

Kategoria:SQL Server


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.

CREATE TABLE Technologie
(
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')

SELECTFROM Technologie
UNION
SELECTFROM TechnologieNet

SELECTFROM Technologie
UNION ALL
SELECTFROM 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:

Plan wykonania instrukcji UNION
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:

Plan wykonania instrukcji UNION ALL
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 DISTINCT * FROM (
SELECTFROM Technologie
UNION ALL
SELECTFROM 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

, 2013-12-20

Komentarze:

paulina (2015-07-24 10:47:20)
świetny artykuł!
Szary (2016-06-22 08:42:42)
Dobry wpis. Szczególnie część poświęcona planom wykonania i wydajności.
Konrad (2016-08-26 10:27:21)
Dzięki wielkie, przydało się :)
Adam (2016-10-08 11:41:49)
Dobrze i prosto wyjaśnione. Super ! Dzięki !
JaFranek (2017-03-15 19:06:07)
Super artykuł, dziekuje
Malwis (2017-07-23 14:13:01)
Swietna pomoc, dzieki!
Mario (2017-08-24 08:25:38)
Bardzo pomocne.
Olgierd (2018-03-09 22:03:53)
Brawo!
Marta (2018-08-20 22:53:36)
Świetny wpis. Szkoda, że tak rzadko spotyka się podobną jakość przeszukując sieć.
Kk (2019-08-02 11:18:10)
Dobrze wyjaśnione, dzięki !
Bart (2019-11-22 08:42:21)
Dzieki za te informacje. były kluczowe
pani_izabela (2020-04-22 11:32:22)
Bardzo dziękuję za jasne tłumaczenie z dobrze dobranym przykładem!
NIGGA (2022-03-17 09:01:58)
Morzna by bylo trohe jasiniej?
Dodaj komentarz
Wyślij
Ostatnie komentarze
Dzieki za rozjasnienie zagadnienia upsert. wlasnie sie ucze programowania :).
Co się stanie gdy spróbuję wyszukać:
SELECT * FROM NV_Airport WHERE Code='SVO'
SELECT * FROM V_Airport WHERE Code=N'SVO'
(odwrotnie są te N-ki)
Będzie konwersja czy nie znajdzie żadnego rekordu?