よく、EXISTSの方が速いのでEXISTSを使うべきと言われていたりしますが、それは間違いです。用途に合わせて使っていくのが正しい使い方になります。
結論
いろいろ調査してみた結果、以下のような使い分けが良いでしょう。
1 2 3 |
別テーブルの情報を出力対象にしたい場合:JOINを使う。 別テーブルの情報を抽出条件に使用し、主テーブルの選択性が高い場合:EXISTSを使う。 別テーブルの情報を抽出条件に使用し、従テーブルの選択性が高い場合:INを使う。 |
MySQLの場合は特殊
なお、Web業界の実務でよく使われるMySQLでは相関サブクエリはかなり遅くなるので、EXISTSを使うのであればJOINを使った方が良いケースが多いようです。(INを使ったサブクエリも内部的にEXISTSに書き変わるようなので、INNER JOINの方が早いのでしょう。)ただ、JOIN + DISTINCTで重複排除処理にコストがかかるようなSQLであれば、EXISTSの方がパフォーマンスに優れる場面が発生するという感じでしょうかね。なので、MySQLの場合はINNER JOINとEXISTSを使い分けましょうという話になるのでしょう。
INとEXITSのサンプル
以下の記事で解説しています。
INとEXITSの仕組みの違い
INは主問い合わせのWHERE句の前、EXISTSは後で処理される。基本思想としては、できるだけ早い段階でデータ量を削ぎ落とせるかを考えることが重要です。
選択性とは?
たくさんの項目の中から特定の値を選ぶ度合いです。例えば、10個の中から1つを選ぶケースは選択性が高いと言えますし、10個の中から8つも選べてしまうケースは選択性が低いと言えます。
IN(「MySQL」だとこの説明の限りではない。)
評価順番が、「副問い合わせ→親問い合わせ」になります。
「従表フィルタの選択性が高くてインデックスが使えてデータを先に削ぎ落とせる場合」はこちらを使う。
JOINとの違い
サブクエリの中の「テーブル2.id」が重複していたとしてもテーブル1には一意の結果を返してくれます。なので、INの中に大量に重複データが含まれてしまっている場合などはパフォーマンスが低下すると言われます。いろいろ言われますが、INは効率が悪いとも言われます。INを使うのであれば、JOINを使った方が良いという意見もあるようです。
1 |
select * from テーブル1 in テーブル1.id in (select テーブル2.id from テーブル2) |
INの中でDISTINCTを使う形が良いのかもしれません。
EXISTS
評価順番が、「親問い合わせ→副問い合わせ」になります。
「主表フィルタの選択性が高い場合」はこちらを使う。また、主表側も従表側もどちらも選択性が低い場合はINではなくEXISTSを使えば良いです。
JOINとの使い分け
結論から言えば下記になります。
1 2 |
別テーブルの情報を出力対象にしたい場合:JOINを使う。 別テーブルの情報を抽出条件に使用するだけの場合:EXISTS、INを使う。 |
JOINでも同じことできるじゃん?
1:1ならJOINでもEXISTSでも結果は変わらないのですが、1:Nの場合は重複した結果が出力されてることになります。DISTINCTやGROUP BYを使えば良いのですが、「DISTINCT」や「GROUP BY」はコストがかかる処理になるのでできれば使いたくはないです。なので、EXISTSを使った方が良いのです。
JOINを使った方が良いケース
ただ、関連テーブルの情報を使いたい場合はJOINを使わざるおえないです。大事なのは使い分けることですね。
この記事へのコメントはありません。