【SQL Server】WHERE EXISTSの使い方

  • このエントリーをはてなブックマークに追加

よくwhere existsの意味を勘違いしている方いるのでここでちょっとまとめて記事にしておきます。

例えば、以下のようなexistを使用したクエリがあったとします。

SELECT * FROM TBL_A
WHERE EXISTS (
   SELECT * FROM TBL_B
   WHERE col1 = ‘hoge’
)

一般的なEXISTSを使用したサブクエリを条件にしたものですが、EXISTS内のサブクエリ内の結果が「真」であれば、SELECT * FROM TBL_Aの結果を返す意味になります。
仮にサブクエリ内の結果が「偽」であればSELECT * FROM TBL_Aの結果はTBL_A内のレコード件数の有無に限らず、0件になります。

では、以下のクエリの場合はどうでしょうか?

SELECT * FROM TBL_A
WHERE EXISTS (
   SELECT *  FROM TBL_B
   WHERE col1 = ‘hoge’
)
AND col_a = ‘foo’

この場合、EXISTS内のサブクエリの外条件に対してEXISTS内のサブクエリで存在チェックを返すことに注意です。

EXISTS使用は速度改善に繋がるのか?

よく、速度改善としてEXISTSを使用すると言われていますが、結論から言うと「NO」です。
むしろ遅くなります。

参照するテーブルのレコード数にもよりますが、数万件、数100万件以上のレコードをもつような大きなテーブルを扱う場合は、速度遅延も顕著になってきます。

例えば以下クエリの例で考えてみましょう。
※以下の2つのテーブルを使用するものとします。
STAFF_MST・・・社員マスタ
KINTAI ・・・勤怠テーブル(過去の出勤データ)

SELECT * FROM STAFF_MST As S
WHERE EXISTS(
     SELECT * FROM  KINTAI As K
     S.STAFF_CD = K.STAFF_CD
 WHERE K.DTE >= ‘2017-04-01’
)

一見、見やすさという観点できれいにまとまったクエリになっていますが、実際はどうでしょうか?

極端な話、上記クエリの場合では最大STAFF_MSTのレコード数 ☓ KINTAIテーブルのレコード数分の比較チェック処理が走る構造になっています。比較するお互いのテーブル内レコード数が多くなれば多くなるほど、処理能力は重くなっていきます。正直、速度改善を目的としてEXISTSを利用するメリットはあまりありません。

では、EXISTSを使用せずに速度改善する方法は他にあるのか?

よく、目にするLEFT JOIN もしくはINNER JOIN の方が遥かに優秀です。
見た目は複雑になりますが、速度という観点では実はEXISTSよりも早いです。

上記クエリをINNER JOIN に置き換えた場合

SELECT * FROM STAFF_MST As S
INNER JOIN (
     SELECT * FROM KINTAI As K
     WHERE K.DTE >= ‘2017-04-01’
} ON S.STAFF_CD = K.STAFF_CD

理由はわかりますでしょうか?

まず、上記のクエリの場合ではINNER JOIN内の処理が優先されます。
つまり、KINTAIテーブルの絞り込みが先に行われた上でSTAFF_MSTとの結合が行われることになります。EXISTSのサブクエリを使用するより、INNER JOIN で結合して比較する方が比較対象件数を減らすことで速度の改善が見込めるというわけです。

当然ながら、その威力を体感するにはレコード件数の多いテーブルを相手にする必要がありますが、日頃から、EXISTSで書けるものはINNER JOIN やLEFT JOIN に置き換えられるという事実、速度改善も見込めるという事実、この2つを覚えておいても損はないと思います。

SNSでもご購読できます。

コメントを残す

*