mysqlキーワードexistsとin

9690 ワード

mysqlではサブクエリをよく使用しますが、サブクエリではinとexistsが使用されます.次に、この2つのキーワードを分析します.
1、existsとinの文法
1.1 exists
sql文にexistsキーワードが表示されると、外観がループクエリされ、クエリはexists条件文が条件に合致しているかどうかを表示します.existsの条件文がレコード行を返すことができる場合、条件は真であり、現在のデータが返されます.逆にexistsの条件文がレコード行に戻らない場合、現在ループされているこのデータは破棄されます.existsの条件はフィルタ条件であり、結果セットを返すことができる場合はtrue、結果セットを返すことができない場合はfalseである.
次のようになります.
select * from user where exists (select 1);

userテーブルのレコードを1つずつ取り出し、サブ条件のselect 1が常にレコード行に戻るため、userテーブルのすべてのレコードが結果セットに追加されるため、select*from user;同じです.
また次のように
select * from user where exists (select * from user where userId = 0);

userテーブルをloopする場合、条件文(select*from user where userId=0)をチェックします.userIdは永遠に0ではないため、条件文は永遠に空のセットに戻り、条件は永遠にfalseであり、userテーブルのすべてのレコードは破棄されます.
not existsはexistsとは逆に、exists条件で結果セットが返されると、loopからのレコードは破棄され、そうでないとloopからのレコードが結果セットに追加されます.総じて、Aテーブルにn個のレコードがある場合、existsクエリは、このn個のレコードを1個ずつ取り出し、nパスexists条件を判断する
1.2、in
inクエリーは複数のor条件の重ね合わせに相当します.これは理解しやすいです.例えば、次のクエリーなどです.
select * from user where userId in (1, 2, 3);

に等しい
select * from user where userId = 1 or userId = 2 or userId = 3;

not inはinとは逆です.たとえば、次のようにします.
select * from user where userId not in (1, 2, 3);

に等しい
select * from user where userId != 1 and userId != 2 and userId != 3;

総じて、inクエリは、サブクエリ条件のレコードをすべて検出し、結果セットがBでmレコードが共有されていると仮定し、サブクエリ条件の結果セットをm個に分解してm回クエリを行う
注目すべきは、inクエリのサブ条件が結果を返すには、次のようなフィールドが1つしかない必要があります.
select * from user where userId in (select id from B);

できない
select * from user where userId in (select id, age from B);

existsにはこの制限はありません
2、existsとinの性能
まず、次の2つのSQL文を考えてみましょう.
1:select * from A where exists (select * from B where B.id = A.id);

2:select * from A where A.id in (select id from B);

クエリー1.以下の疑似コードを変換でき、理解しやすい
for ($i = 0; $i < count(A); $i++) {

  $a = get_record(A, $i); # A       

  if (B.id = $a[id]) #       

    $result[] = $a;

}
return $result;

つまり、クエリ1は主にBテーブルのインデックスを用いており、Aテーブルがクエリの効率にどのように影響するかは大きくないはずです.
クエリー2の場合、Bテーブルのすべてのidが1,2,3であると仮定し、クエリー2は
select * from A where A.id = 1 or A.id = 2 or A.id = 3;

これはよく理解して、ここで主にAのインデックスを使って、B表はどのようにクエリーに対してあまり影響しません.
次にnot existsとnot inを見てみましょう
1. select * from A where not exists (select * from B where B.id = A.id);

2. select * from A where A.id not in (select id from B);

クエリー1を見ると、やはり上と同じようにBのインデックスが使われていますが、クエリー2については、次の文に変換できます.
select * from A where A.id != 1 and A.id != 2 and A.id != 3;

not inは範囲クエリーであることがわかります.この!=の範囲のクエリはいかなる索引を使うことができなくて、A表のすべての記録を言うのと同じで、すべてB表の中で1回遍歴して、B表の中でこの記録が存在するかどうかを確認します
だからnot existsはnot inより効率が高い
mysqlのin文は外見と内表をhash接続し、exists文は外表に対してloopループを行い、loopループのたびに内表をクエリーします.いつもexistsはin文より効率が高いと言われていますが、この言い方は正確ではありません.これは環境を区別します.
  • クエリーの2つのテーブルのサイズが同じである場合、inとexistsの差は大きくありません.
  • 2 2 2つのテーブルのうち1つが小さく、1つが大きなテーブルである場合、サブクエリテーブルの大きいものはexists、サブクエリテーブルの小さいものはin
  • を用いる.
    例えば、表A(小表)、表B(大表)
    case 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    。 
       

    case 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より速いです.
    3、まとめ
    in実行順序:まずinのサブクエリを実行し、我々の最外層ループとして、メインクエリを内層ループexistsとする:メインクエリを最外層ループとして、サブクエリを最内層ループとする
    一方,我々の時間的複雑さによれば,最外層サイクルが内層サイクルより小さい場合,使用時間は相対的に少ない.
    結論:永遠の小表駆動大表が最良の選択方式である