アンチパターン例
以下のようにwhere句の条件だけ少し変えてUNIONでくっつけてデータを取得するSQLをやってしまいがちになります。
1 2 3 4 5 6 7 |
SELECT 列x、列y as 別名 FROM テーブル1 WHERE 条件A UNION ALL SELECT 列x、列Z as 別名 FROM テーブル1 WHERE 条件B; |
使いたくなるケース
「条件Aでは、列yを抜き出す。条件Bでは列zを抜き出す。」などのような場合(例えば、年度によって価格改定があるなど)
デメリット
パフォーマンスの遅延
SQLの発行回数こそ1回とは言え、内部的には複数のSELECT文を実行するものとして解釈されテーブルへのアクセス回数が増えて「ストレージのI/O物理コスト」が膨らむ傾向にある。
また、インデックススキャンならまだしも、SQLの条件によってはフルテーブルスキャンが2度実行されてしまうことになりますし、読み取りコストはデータ件数に応じて増大していってしまいます。
読みづらい
また、そもそも似たようなSQLが2度発行されているような構文になっており冗長に見えて可読性が低いです。
CASE式を使った書き換え
以下のように書き換えるとパフォーマンスは2倍に上がります。安易にUNIONに頼らないようにすると良いでしょう。
1 2 3 4 |
SELECT 列x, CASE WHEN 条件A THEN 列y WHEN 条件B THEN 列z END AS 別名 FROM テーブル1; |
WHERE句で条件分岐をさせるという考え方もあるかもしれませんが、できる限りSELECT句で条件分岐させた方が無駄なスキャンが発生しないのでパフォーマンスが良くなるのでその辺も意識して実装を行えるとさらにプロに近づきます。
実行計画も上記のSQLはかなりスッキリします。
UNIONとCASEの違い
UNIONの場合は、文を単位に分岐させているので手続的型言語的な発想の分岐になります。対してCASEによる分岐は式をベースにした思考法になるのでより集合志向型言語であるSQLの言語的な考え方にマッチした実装方法になります。CASEで済むのであれば、UNIONを使わずCASE式を多用するようにしていった方が良いでしょう。
まとめ
- 手続き型言語で言うIF文や条件分岐が出てきたらまずはCASE式で実装できないか頭を捻らせて考えてみる。
- 出来るだけSELECT句に寄せられないか考えてみる。
この記事へのコメントはありません。