SQLにおいて、しばしば
「INよりEXSITSを使った方がインデックスが使用されるので性能がでる」
ということが言われます。
これについて、なぜそう言ったことが言えるのかを解説していきます。
テーブルAとテーブルBのあるカラムを比較し、テーブルAにもテーブルBにも存在する値のみを抽出するSQLを考えていきます。
INとEXISTSを使ったパターンはそれぞれ以下のようになります。
SELECT * From table_a WHERE col IN ( SELECT col FROM table_b );
SELECT * From table_a WHERE col EXISTS ( SELECT * FROM table_b WHERE table_a.col = table_b.col );
この場合、一般的にEXISTSを使用した後者のクエリの方が早くなります。
この理由をそれぞれのクエリがどのように実行されるのかを見ることで解明していきましょう。
INを使ったパターンの挙動
INの場合、まずサブクエリが実行されます。
table_bからすべてのcolの値を検索している部分ですね。
この結果が一時的にDBのメモリにワークテーブルとして展開されます。
次に外側のクエリが実行されます。
table_a中に存在するcolが、先ほど作成したワークテーブルの中に存在するかを検索します。
この際、ワークテーブルにはインデックスが貼られません。
そのため、ワークテーブル内をフルスキャンすることになります。
ワークテーブルの行数が多ければ多いほど実行に時間がかかることがわかります。
EXISTSを使ったパターンの挙動
EXISTSを使った場合も同様にサブクエリが実行されます。
ただし、この際行われるのは、現在みているtable_aのcolと同じcolを持つtable_bのレコードが存在するかです。
この処理は、table_bのインデックスが使用されるので、インデックススキャンが行われます。
table_bの行数にもよりますが、一般的にはフルスキャンよりも高速になります。
(table_bのcolにインデックスが作成されている前提となります。)
実際の挙動は実行計画を確認しよう
一般的にこの二つのSQLは上記のような動作をします。
しかし、これはあくまで一般的であり、DBMSやオプティマイザの仕様によって微妙に異なってきます。
なので、実際にどのような挙動を取っているかは実行計画を確認するようにしましょう。