【MySQL】SQLで(NOT)INは、遅いらしいので(NOT)EXISTSを使うべき!?

mysql

以前、SQLのNOT IN(~以外)-IN(含んでいる)という記事をメモ程度に書いたんですが、たまたまSQLについて調べてみたら以外にNOT IN(~以外)とIN(含んでいる)ってどうやらパフォーマンスが悪いようです。
*以下 (NOT)INはNOT IN と INの両方を指す。

前に記事はほんと、今思えば大した記事でもないんですが、せっかくなんでそのまま残してあります。(笑)

また、自分もそんなSQL文など詳しい訳ではなくていろんな情報を精査して得た知識を自分なりに記事にしたので、間違えてる可能性もあります。

SQLの(NOT)INの遅い理由

(NOT)INがなぜ遅いかというとデータベースに登録されている対象のテーブルの全レコードを先頭から順番に読み込みしなければならないからです。

	SELECT * FROM TEST WHERE id NOT IN(20,30);
	SELECT * FROM TEST WHERE id IN(20,30);

例えば、上記のようなSQLがあった場合に、idが20、.30以外のデータを取得するのに最初から最後のレコードまでidをチェックするようです。

まぁこれが100件とかならまだしも数十万件とか膨大なレコード数になればそりゃ遅くなるということです。

(NOT)EXISTSで書き直しみてる

ということで、MySQLで(NOT)INの代わりに(NOT)EXISTSを使うと速いんじゃない?ってことをネットで券検索するとちらほら聞きいたので、調べてみた。

下記のサンプルは値が存在した場合を条件にしたのでNOT EXISTSではなく、EXISTSで記述しています。

使用テーブル:
Member(メンバーテーブル)
id(メンバーのID)
name(メンバーの名前)

Access_log(アクセスログのテーブル)
id(メンバーのID)
date(ログの時間)

–1.遅い
SELECT Member.name
FROM Member
WHERE id IN (SELECT id
FROM Access_log);

–2.速い
SELECT Member.name
FROM Member
WHERE EXISTS (SELECT *
FROM Access_log
WHERE Access_log.id = Member.id);

例としてEXISTSで、MemberテーブルとAccess_logテーブルがあり、Access_logテーブルに登録されているメンバーIDにMemberテーブルのメンバーIDが存在するようであればそのメンバーの名前を抽出するSQLです。

(NOT)EXISTSが早い理由

(NOT)EXISTSが早い理由として挙げられるが、(NOT)INのように、全レコードを検索するのではなく、(NOT)EXISTS は条件に合致する行を見つけたらそこで検索を打ち切る為、全レコードを検索の必要がないので高速だといわれています。

(NOT)EXISTSが記述に関して

EXISTSの記述として、ブクエリ内では、SELECT * を使うのが一般的のようです。

1.EXISTS (SELECT * FROM …)
2.EXISTS (SELECT 列名 FROM …)
3.EXISTS (SELECT 定数 FROM …)

注意点

ただ注意点として、INもEXISTSも結果が一緒になる場合もありますが、意味が変わってくることもあるので注意してください。自分もここら辺に関してはよく分かりませんが下記のサイトを参考にしてみてください。