SQL IN
- clauseでOR
またはWhere
のどちらがパフォーマンスが優れている大きなデータベースを扱う場合
それらの実行方法に違いはありますか?
次のパフォーマンスの違いを知りたいと思います。
WHERE foo IN ('a', 'b', 'c')
WHERE foo = 'a' OR foo = 'b' OR foo = 'c'
MySQLのマニュアル に従って、値が定数の場合IN
はリストをソートし、バイナリ検索を使用します。 OR
は、それらを特定の順序なしに1つずつ評価すると想像します。したがって、IN
は状況によっては高速です。
知る最良の方法は、データベースの両方を特定のデータでプロファイリングして、どちらが速いかを確認することです。
1000000行のMySQLで両方を試しました。列にインデックスが付けられている場合、パフォーマンスに目立った違いはありません。両方ともほとんど瞬時です。列にインデックスが付けられていない場合、次の結果が得られました。
SELECT COUNT(*) FROM t_inner WHERE val IN (1000, 2000, 3000, 4000, 5000, 6000, 7000, 8000, 9000);
1 row fetched in 0.0032 (1.2679 seconds)
SELECT COUNT(*) FROM t_inner WHERE val = 1000 OR val = 2000 OR val = 3000 OR val = 4000 OR val = 5000 OR val = 6000 OR val = 7000 OR val = 8000 OR val = 9000;
1 row fetched in 0.0026 (1.7385 seconds)
したがって、この場合、ORを使用する方法は約30%遅くなります。用語を追加すると、差が大きくなります。他のデータベースや他のデータでは結果が異なる場合があります。
見つけるための最良の方法は、実行計画を見ることです。
Oracleで試しましたが、まったく同じでした。
CREATE TABLE performance_test AS ( SELECT * FROM dba_objects );
SELECT * FROM performance_test
WHERE object_name IN ('DBMS_STANDARD', 'DBMS_REGISTRY', 'DBMS_LOB' );
クエリはIN
を使用しますが、実行計画ではOR
を使用すると言われています。
--------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 8 | 1416 | 163 (2)| 00:00:02 |
|* 1 | TABLE ACCESS FULL| PERFORMANCE_TEST | 8 | 1416 | 163 (2)| 00:00:02 |
--------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("OBJECT_NAME"='DBMS_LOB' OR "OBJECT_NAME"='DBMS_REGISTRY' OR
"OBJECT_NAME"='DBMS_STANDARD')
OR演算子は、INのように等しいだけでなく、多くの条件を許可するため、IN構造よりもはるかに複雑な評価プロセスが必要です。
ORで使用できるものの、IN:と互換性のないものは次のとおりです。以上、以下、以下、LIKEなど、Oracle REGEXP_LIKEのようなもの。さらに、条件が常に同じ値を比較するとは限らない可能性があることを考慮してください。
クエリオプティマイザーでは、同じ値に=演算子を使用して複数の条件でOR演算子を定義する構造体のみであるため、IN演算子の管理が簡単です。 OR演算子を使用する場合、オプティマイザーは常に同じ値に対して=演算子を使用しているとは見なさない可能性があり、さらに深く複雑なエラボレーションを実行しない場合、おそらく関係するすべての条件で同じ値の=演算子のみが存在する可能性があることを除外します。その結果、前述のバイナリ検索のような最適化された検索方法が除外されます。
[編集]おそらくオプティマイザーは最適化されたIN評価プロセスを実装していないかもしれませんが、これは一度発生する可能性があることを除外しません(データベースバージョンのアップグレードで)。したがって、OR演算子を使用すると、最適化されたエラボレーションは使用されません。
Oracleは、効率の悪い方(どちらか)をもう一方に変換するのに十分賢いと思います。したがって、答えはむしろそれぞれの読みやすさに依存するべきだと思います(IN
が明らかに勝つと思う場所)
比較する値が少ない場合、OR
は理にかなっています(読みやすさの観点から)。 IN
は、特に便利です。値を比較する動的ソースがある場合。
別の方法は、JOIN
を一時テーブルで使用することです。
必要なインデックスがあれば、パフォーマンスが問題になるとは思いません。
多数のOR(350)でSQLクエリを実行しました。 Postgresはそれを行います437.80ms。
INを使用します。
23.18ms