helloworlds

not a noun, it's a verb

【SQL】SQLにおける条件分岐とは

前回の続きで第三章の主要点をまとめていきたいと思います。 (具体的なテーブル表など割愛させてもらうことが多いです)

o21o21.hatenablog.jp

今回は、「条件分岐について」です。

少しSQLが書けるようになるとパフォーマンスの考慮が気になってしまいます。 なにか条件があるとUNIONをすぐ使用して、「ほんとにUNIONでいいのかな?」など疑問が湧いてくることがあるかと思います。

思考が組み立てやすいので多用することは仕方のないことですが、パフォーマンスに欠点を抱えてしまうことはありがちです。

こうしたとき、実行計画を気にかけてみるようにしました。 実際には内部的に複数回のSELECT文を実行してしまっている!とか気づきがあるかもしれません。

例えばこのようなSQLがあったとします。 (ネーミングセンスがありません...w)

SELECT name, year
  FROM People
WHERE year <= 1990
UNION ALL
SELECT name, year
  FROM People
WHERE year >= 1991;

このSQLだとPeopleテーブルに対して2度のアクセスを実行しています。 フルスキャン実行され読み取りコストが大幅に上がります。 キャッシュに保持されることも想定されますが、大抵テーブルサイズが大きくなるほどキャッシュヒット率は悪くなります。

そしたらどうしたらいいのでしょうか?

SELECT句で条件分岐をする

SELECT name, year,
               CASE WHEN year <= 1990 THEN 'オールド'
                         WHEN year >= 1991 THEN 'ヤング'
FROM People;

このSQLは先程のSQLと同じ結果が出力されます。 が、こちらのほうがパフォーマンスは数段良いです。

UNIONによる分岐は、SELECTの単位で分岐させています。 CASEによる分岐は、の単位で分岐させています。(こちらがベター)

SQLを書く時、「IFを使えるのではないか?」と自答してみましょう。 そして使えるのであればCASE式を使えると覚えておきましょう。

それでもUNIONを使用するケースとは

シンプルに言うと、「マージされるSELECT文同士で使用するテーブルが異なる場合」です。

このようなSQLです。

SELECT co_1
  FROM Table_A
WHERE col_2 = 'a'
UNION ALL
SELECT co_3
  FROM Table_B
WHERE col_4 = 'b';

また、場合によっては「複数のインデックススキャン対1回のフルスキャン」が考えられます。

これに関しては、テーブルのサイズが大きくUNIONを使用してWHERE条件の選択率が十分に小さい場合はUNIONが良いでしょう。

まとめ

もともとUNIONは条件分岐を行うために導入されたものではないこと。 プログラミング言語を扱う際は、「文」に思考がまわります。SQLの場合は、「式」であることを頭に入れておきましょう。 できるだけストレージへのI/Oを減らせるかが重要です。

  • 前回の記事

o21o21.hatenablog.jp

  • 第一章

o21o21.hatenablog.jp