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ライフを!