SQLクエリにおけるinとexistsの違い分析

3520 ワード

select*from A where id in(select id from B)
select*from A where exists(select 1 from B where A.id=B.id)
上記の2つの場合、inはメモリ内で比較を遍歴していますが、existsはデータベースを検索する必要がありますので、Bテーブルのデータ量が大きい場合、existsの効率はinより優れています。
1、select*from A where id in(select id from B)
in()は一回だけ実行して、Bテーブルの中のすべてのidフィールドを検出してキャッシュします。その後、AテーブルのIDがBテーブルのIDと等しいかどうかを確認し、等しい場合はAテーブルの記録をAテーブルのすべての記録に遍歴するまで、結果を集中する。そのクエリのプロセスは以下のようなものです。

List resultSet={};
Array A=(select * from A);
Array B=(select id from B);

for(int i=0;i<A.length;i++) {
   for(int j=0;j<B.length;j++) {
      if(A[i].id==B[j].id) {
         resultSet.add(A[i]);
         break;
      }
   }
}
return resultSet;

Bテーブルのデータが大きい時はin()を使うには適していません。Bテーブルのデータは全部一回の遍歴があります。A表は10000本の記録があり、B表は100000本の記録があります。それでは最大10000*1000回を遍歴する可能性があります。効率が悪いです。また、A表は10000本の記録があり、B表は100本の記録があります。最大10000*100回を遍歴する可能性があります。遍歴回数が大幅に減少し、効率が大幅に向上します。
結論:in()はAテーブルデータよりBテーブルが小さい場合に適しています。
2、select*from A where exists(select 1 from B where A.id=B.id)
exists()はA.length回を実行します。exists()結果集はキャッシュされません。exists()結果集の内容は重要ではありません。重要なのは、その内の照会文の結果集が空か非空か、空ならfalseに戻ります。非空ならtrueに戻ります。そのクエリのプロセスは以下のようなものです。

List resultSet={};
Array A=(select * from A);

for(int i=0;i<A.length;i++) {
   if(exists(A[i].id) {  // select 1 from B where B.id=A.id
       resultSet.add(A[i]);
   }
}
return resultSet;

BテーブルがAテーブルのデータより大きい場合は、exists()を使用するのに適しています。それほど多くのエルゴード操作がないので、もう一回照会すればいいです。例えば、A表に10000条の記録があり、B表に100000条の記録があると、exists()はA表のidがB表のidと等しいかどうかを10000回実行します。例えば、A表は10000本の記録があります。B表は100000万本の記録があります。それではexists()はまだ10000回実行します。A.length回だけ実行します。B表のデータが多いほど、exists()に適して効果を発揮します。更に例えば:A表は10000本の記録があり、B表は100本の記録があります。exists()は10000回実行します。in()を使って10000*100回を遍歴したほうがいいです。in()はメモリの中で比較を遍歴しているので、exists()はデータベースを調べなければなりません。
結論:exists()AテーブルよりBテーブルが大きい場合に適しています。
AテーブルのデータがBテーブルのデータと同じ大きさであれば、inとexistsの効率は同じです。どれを選んで使ってもいいです。記録を挿入する前に、この記録が既に存在しているかどうかを確認し、記録が存在しない場合のみ挿入操作を行い、EXISTS条件文を使用して挿入重複記録を防ぐことができます。insert into A(name,age)selectname,age from B where not exists(select 1 from A where A.id=B.id)
EXISTSとINの使用効率の問題は、通常、INがインデックスを逸脱しないため、existsを採用するのがinより効率が高いです。しかし、実際の状況を見て、具体的に使用すると、INは外観が大きく、内部表が小さい場合に適しています。EXISTSは、見た目が小さく、中身が大きい場合に適しています。
existsについて:
EXISTSは、少なくとも1行のデータが戻ってくるかどうかを確認するために使用されています。このサブクエリは、実際にはデータを返すのではなく、TrueまたはFalseの値を返します。EXISTSはサブクエリを指定し、行の存在を検出します。文法:EXISTS subqueryパラメータ:subqueryは制限されたSELECT文である。結果のタイプ:Booleanは、サブクエリが行を含む場合、TRUEに戻り、そうでなければFLASEに戻ります。結論:select*from A where exists(select 1 from B where A.id=B.id)EXISTS(NOT EXISTSを含む)のサブ句の戻り値は、bollan値です。EXISTS内部にはサブクエリ文(SELECT...FROM...)がありますが、EXISTの内部検索文と言います。検索文は結果セットを返します。EXISTSサブ句は、その内のクエリ文の結果に基づいて空または空をセットし、ブール値を返します。外部クエリテーブルの各行を、内部クエリに代入して検証し、内部クエリが返された結果が非空の値を取れば、EXISTSサブ句はTRUEに戻ってきます。この行は、外部クエリの結果行として使用できます。そうでなければ、結果としては使用できません。分析器はまず文の最初の単語を見ます。最初の単語がSELECTキーワードであることを発見したら、FROMキーワードにジャンプして、FROMキーワードで表名を見つけて、表をメモリに入れます。続いてWHEREキーワードを探して、もし見つけられないならばSELECTに戻ってフィールドの解析を探して、もしWHEREを探し当てるならば、その中の条件を分析して、完成した後に更にSELECT分析フィールドに帰ります。最後に私たちが欲しい虚構の表を作ります。WHEREキーワードの後ろにあるのは条件式です。条件式の計算が完了すると、0または0ではなく、0が本当で、0がfalseです。同じWHEREの後の条件にも戻り値があり、真か偽かは、次の執がSELECTを実行しないことを確定する。分析器はまずキーワードSELECTを見つけて、FROMキーワードにジャンプしてSTUDENT表をメモリに導入し、ポインタを通して第一の記録を見つけて、次にWHEREキーワードを見つけて条件式を計算します。もしそれではこの記録を虚表に入れるなら、針は次の記録を指します。偽の場合は、ポインタは直接に次のレコードを指し、他の操作は行わない。完全なテーブルを検索して検索した仮想テーブルをユーザーに返します。EXISTSは条件式の一部であり、戻り値もあります。