
UNION UNION ALL 違い
というキーワードで検索する人は主に以下を知りたいはずです。
- 2つの演算子がどのように結果を変えるか(重複の扱い)
- パフォーマンスにどれくらい差があるか
- 実務でどちらを使うべきか
本記事では上記の疑問に対して、Oracleを例に違い→実例→実践的な使い分けまでを網羅的に解説します。
UNIONとUNION ALLの違い
UNION
:複数のSELECT
の結果を結合し、重複行を取り除く(内部的にはDISTINCT
相当の処理が行われる)。UNION ALL
:複数のSELECT
の結果をそのまま連結する。重複は排除されない。
一言で言えば重複を取り除くかどうかが主な違いで、UNIONは重複を取り除きUNION ALLは重複を取り除きません。
UNIONとUNION ALLの違いを実例から確認
サンプルデータの準備(例)
CREATE TABLE emp_a (id NUMBER, name VARCHAR2(20));CREATE TABLE emp_b (id NUMBER, name VARCHAR2(20));
INSERT INTO emp_a VALUES (1, '佐藤');INSERT INTO emp_a VALUES (2, '鈴木');INSERT INTO emp_a VALUES (4, NULL);
INSERT INTO emp_b VALUES (2, '鈴木');INSERT INTO emp_b VALUES (3, '高橋');INSERT INTO emp_b VALUES (4, NULL);
COMMIT;
UNION
の例
SELECT id, name FROM emp_aUNIONSELECT id, name FROM emp_b;
結果(説明):
- (1, 佐藤)
- (2, 鈴木) — emp_a と emp_b にある重複が1行にまとめられる
- (3, 高橋)
- (4, NULL) — NULLも1行にまとめられる
UNION ALL
の例
SELECT id, name FROM emp_aUNION ALLSELECT id, name FROM emp_b;
結果(説明):
- (1, 佐藤)
- (2, 鈴木) — emp_a の行
- (4, NULL) — emp_a の行
- (2, 鈴木) — emp_b の行(重複がそのまま残る)
- (3, 高橋)
- (4, NULL) — emp_b の行(重複がそのまま残る)
UNIONとUNION ALLのパフォーマンスの違い
UNION
は重複排除のための追加処理(ソートかハッシュ集約)を行うので、計算コストが高くなりがちです。データ量が増えるほど、差は大きくなります。UNION ALL
は単純に結果を連結するだけなので、基本的に高速です。
Oracleの実行計画では、UNION
を使うとSORT UNIQUE
やHASH UNIQUE
のような演算子が登場することがあり、これがコスト増の主因になります。
結論(パフォーマンス面):重複の可能性がない(あるいは重複を気にしない)場合はUNION ALL
を選ぶべきです。不要なUNION
の使用は避ける。
UNIONとUNION ALLの構文上のルールと注意点
結合時のカラム数と型の互換性
- 結合するすべての
SELECT
は同じ数の列を返す必要があります。 - 同じ順序で、互換性のあるデータ型でなければなりません(暗黙の型変換が働く場合もありますが、安全のため明示的にキャストすることが推奨されます)。
列名は先頭のSELECTから決まる
- 結果セットの列名(ヘッダ)は、最初の
SELECT
句の列名が使われます。
ORDER BYは最終結果に適用
ORDER BY
は最終結果に対して適用されます。各サブSELECT
にORDER BY
を書いても、最終結果の並びは保証されません。
UNION時のNULLの扱い
UNION
(重複排除)の際、NULLは等価とみなされるため、複数の列値がすべてNULLの行は重複として扱われ、1行にまとめられます。
例:
SELECT NULL, 1 FROM ...
が複数行ある場合、UNION
では1行にまとめられます。
ORDER BY・列名・型の扱い(補足)
ORDER BY
は全体に対して効くため、個々のサブクエリの並びを期待するのは間違いです。サブクエリにORDER BY
を書いても最終結果の保証にはならないので注意してください。- 列のデータ型が微妙に異なる場合、Oracleは暗黙的に変換しますが、想定外の変換や精度損失が起こることがあります。安全のため
CAST
で合わせたほうがベターです。
UNIONとUNIONALLのよくある誤解
- 誤解:
UNION
は単にUNION ALL
の別名である。 → 訂正:UNION
は重複を排除するために追加処理が走る。 - 誤解:NULLは重複判定で常に異なると扱われる。 → 訂正:
UNION
の重複判定ではNULLは等価とみなされる(同じNULL同士は重複としてまとめられる)。
UNIONとUNION ALLの使い分け
重複が論理的にあり得ない(別ソースのIDが被らない)
→ UNION ALL
を使う。余計なオーバーヘッドを避けられます。
重複を必ず排除したい(名寄せのような場合)
→ UNION
または UNION ALL
+ 明示的な重複排除(ROW_NUMBER()
で一意を決める)
集計を取りたい(重複をまとめて集計する)
UNION ALL
で連結後にGROUP BY
する方がパフォーマンスが良いケースがあります(特に各ソースの行数が大きく、並列処理が効く場合)。
UNION・UNION ALLまとめ
- 重複を排除したいなら:
UNION
(ただしパフォーマンスコストあり)。 - 重複を許容する、または重複が発生しないと確信できるなら:
UNION ALL
(高速)。 - 結合するSELECTは列数・型を合わせる。
UNION・UNION ALLのFAQ
Q1. UNION
と DISTINCT
の違いは?
A: 機能的には同じ(重複排除)。UNION
は複数のSELECT
を結合して結果全体で重複を排除する操作です。SELECT ... DISTINCT
は単一のSELECT
の結果に対して重複排除を行います。
Q2. どちらが速いですか?
A: 一般にUNION ALL
。ただし実際の速度はデータ量、インデックス、統計、実行計画に依存します。
以上で本記事の解説を終わります。
よいITライフを!