MySQL inとexistsどちらが効率的ですか
2018 ワード
多くの人がexistsの効率がinより高いと言っていますが、そうかどうか見てみましょう.
MySQLのin文は外見と内表をhash接続し、exists文は外表に対してloopループを行い、loopループのたびに内表をクエリーします.
まず、この2つの文を見てみましょう.
1、
1番目のクエリは、実際にはor文に相当し、Bテーブルにidが1、2、3の3つのレコードがあると仮定すると、上記の文は等価に変換されます.
これはよく理解できますが、主にAテーブルのインデックスを使用しています.Bテーブルのサイズはクエリーの効率にあまり影響しません.
2番目のクエリについては、以下の疑似コードに変換することができ、理解しやすい
主にBテーブルのインデックスが使用されており、Aテーブルのサイズはクエリの効率にあまり影響しないことがわかります.
次にnot inとnot existsを見てみましょう
1、
not inは範囲クエリーです.!=インデックスは一切使用できませんので、Aテーブルの各レコードは、Bテーブルに1回遍歴して、Bテーブルにこのレコードが存在するかどうかを確認しますが、not existsは上記と同じようにBのインデックスを使用しているので、どんな場合でもnot existsはnot inより効率的です.
まとめ:
クエリの2つのテーブルのサイズが同じである場合、inとexistsでは効率の差は大きくありません.
2つのテーブルのうち1つが小さく、1つが大きい場合、サブクエリテーブルが大きい場合はexists、サブクエリテーブルが小さい場合はinを使用します.
例えば、表A(小表)と表B(大表)があります
1:
だからその時計が大きくてもnot existsを使うのはnot inより速いです.
MySQLのin文は外見と内表をhash接続し、exists文は外表に対してloopループを行い、loopループのたびに内表をクエリーします.
まず、この2つの文を見てみましょう.
1、
select * from A where A.id in (select id from B);
2、 select * from A where exists (select * from B where B.id = A.id);
1番目のクエリは、実際にはor文に相当し、Bテーブルにidが1、2、3の3つのレコードがあると仮定すると、上記の文は等価に変換されます.
select * from A where A.id = 1 or A.id = 2 or A.id = 3;
これはよく理解できますが、主にAテーブルのインデックスを使用しています.Bテーブルのサイズはクエリーの効率にあまり影響しません.
2番目のクエリについては、以下の疑似コードに変換することができ、理解しやすい
for ($i = 0; $i < count(A); $i++) {
$a = get_record(A, $i); # A
if (B.id = $a[id]) #
$result[] = $a;
}
return $result;
主にBテーブルのインデックスが使用されており、Aテーブルのサイズはクエリの効率にあまり影響しないことがわかります.
次にnot inとnot existsを見てみましょう
1、
select * from A where A.id not in (select id from B);
2、 select * from A where not exists (select * from B where B.id = A.id);
明らかに、クエリ1については、Bテーブルidフィールドが1,2,3であると仮定したように、次の文に変換できる.select * from A where A.id != 1 and A.id != 2 and A.id != 3;
not inは範囲クエリーです.!=インデックスは一切使用できませんので、Aテーブルの各レコードは、Bテーブルに1回遍歴して、Bテーブルにこのレコードが存在するかどうかを確認しますが、not existsは上記と同じようにBのインデックスを使用しているので、どんな場合でもnot existsはnot inより効率的です.
まとめ:
クエリの2つのテーブルのサイズが同じである場合、inとexistsでは効率の差は大きくありません.
2つのテーブルのうち1つが小さく、1つが大きい場合、サブクエリテーブルが大きい場合はexists、サブクエリテーブルが小さい場合はinを使用します.
例えば、表A(小表)と表B(大表)があります
1:
select * from A where cc in (select cc from B) , A cc ;
select * from A where exists(select cc from B where cc=A.cc) , B cc 。
2: select * from B where cc in (select cc from A) , B cc ;
select * from B where exists(select cc from A where cc=B.cc) , A cc 。
not inとnot existsクエリー文がnot inを使用している場合、内外のテーブルはインデックスを使用せずに全テーブルスキャンされます.not extstsのサブクエリは、テーブルのインデックスにも使用できます.だからその時計が大きくてもnot existsを使うのはnot inより速いです.