1

TABLE1 に 100 万のエントリがあるとします。

Table2 には 50k のエントリがあります。

SELECT stringVal 
FROM TABLE2 
WHERE idTable2=5

選択の結果:

5
4

その選択は0.02s処理に時間がかかりますが、IN内で使用すると最大で20.20s

SELECT count(*) 
FROM TABLE1 
WHERE stringVal IN (
   SELECT stringVal FROM TABLE2 where idTable2=5);

このように使用すると、0.02秒で処理されます

SELECT count(*) 
FROM TABLE1 
WHERE stringVal IN (5,4);

ここで物事がどのように機能するかを誰かに説明してもらえますか?

4

4 に答える 4

3

あなたのRDBMSはあなたのクエリをうまく実行していないと思います.他のRDBMS(SQL Serverなど)は、サブクエリが外部クエリと相関していない場合、内部に結果を具体化し、サブクエリを繰り返し実行しないことを確認できます. 例えば

select *
    , (select count(*) from tbl) -- an smart RDBMS won't execute this repeatedly
from tbl

独立したクエリであるため(外部のクエリとは相関していない)、優れたRDBMSはカウントを繰り返し実行しません。

すべてのオプションを試してみてください。

まず、EXISTS を試してください。RDBMS の EXISTSは、IN よりも高速である可能性があります。ただし、IN は EXISTS よりも高速であることに遭遇しました。例:最も自然なクエリ (つまり、(LEFT JOIN の代わりに INNER JOIN を使用する)) が非常に遅い 理由 Quassnoi による同じ観察 (IN は EXISTS よりも高速です): http://explainextended.com /2009/06/16/in-vs-join-vs-exists/

SELECT count(*) 
FROM TABLE1 
WHERE 
   -- stringVal IN 
   EXISTS(
       SELECT * -- please, don't bikeshed ;-)
       FROM TABLE2            
       where 
             table1.stringVal = table2.stringVal -- simulated IN
             and table2.idTable2 = 5);

2番目に、INNER JOINを試してください。重複がない場合はこれを使用するか、DISTINCTを使用して重複を削除します。

SELECT count(*) 
FROM TABLE1 
JOIN (
       SELECT DISTINCT stringVal -- remove duplicates
       FROM TABLE2            
       where table2.idTable2 = 5 ) as x
ON X.stringVal = table1.stringVal

3番目に、自分で行を具体化してみてください。SQL Server で同じ問題が発生しました。具体化された行のクエリは、別のクエリの結果をクエリするよりも高速です。

クエリ結果をテーブルにマテリアライズし、結果に IN を使用する例を確認してください。別のクエリ アプローチで IN を使用するよりも高速であることがわかります。投稿の下部を読むだけで済みます。 -is.html

例:

SELECT distinct stringVal -- remove duplicates
into anotherTable
FROM TABLE2            
where idTable2 = 5;

SELECT count(*) 
FROM TABLE1 where stringVal in (select stringVal from anotherTable);

上記は Sql Server と Postgresql で動作していますが、他の RDBMS では次のようになります。

create table anotherTable as
SELECT distinct stringVal -- remove duplicates
FROM TABLE2            
where table2.idTable2 = 5;


select count(*)
from table1 where stringVal in (select stringVal from anotherTable)
于 2012-06-13T09:47:26.040 に答える
1

私はサブクエリが大好きですが、非常に強力ですが、反復ごとにクエリを完全に評価する必要があるため、非常に低速です。(実装による)

これが、彼らが私の/私たちの最後の手段である理由です.

一部のSQL実装は非常に優れており、サブクエリをキャッシュしますが、それがどれほど安全かはよくわかりませんが、それでもこの構造全体をトラバースする必要があり、構造が適切に最適化されていない場合、ネストすると2次でも立方時間もかかりますそれらの十分な...

SELECT stringVal 
FROM TABLE2 
WHERE idTable2=5

これは線形時間 O(n) です。SQL データベースに統計情報が格納されている場合は、定数 O(1) になることもありますが、そうではないと仮定して、すべての行を検索し、where に一致するすべての行を返します。句。

SELECT count(*) 
FROM TABLE1 
WHERE stringVal IN (
   SELECT stringVal FROM TABLE2 where idTable2=5);

サブクエリがキャッシュではないと仮定すると、各行で評価されます。多くの評価がある場合、多くの無駄な繰り返し計算があり、そのキャッシュであっても、構造は検索に最適ではない可能性があります。文字列のリストで、文字列も比較していることに言及してください。

SELECT count(*) 
FROM TABLE1  
WHERE stringVal IN (5,4);

サブクエリはまだ評価中ですが、その定数式は基本的にオーバーヘッドがまったくないため、IO を実行したり、ロックなどを処理したりする必要はありません :)

于 2012-06-13T08:50:37.550 に答える
0

これは、あなたが探していたのと同じ種類の結果を与える単純な結合です。これは多くの異なる状況に適用でき、これにより別のテーブルに対してクエリを実行する必要がなくなります。

SELECT COUNT(*)
FROM TABLE1 INNER JOIN TABLE2 ON TABLE1.'COLUMN' = TABLE2.'COLUMN' AND TABLE2.IDTABLE2=5 
WHERE 'WHATEVER YOU WANT'

'COLUMN'を、両方のテーブルで参照される列(通常はIDまたは主キー)に置き換えます。

于 2012-11-14T21:35:33.540 に答える
0

これを試して

SELECT count(*) FROM TABLE1 where EXISTS
(SELECT 1 FROM TABLE2 where idTable2=5 and stringVal = TABLE1.stringVal  );

TABLE1 テーブルと TABLE2 テーブルの両方に stringVal のインデックスを作成する必要があります。

于 2012-06-13T08:45:54.647 に答える