web-dev-qa-db-ja.com

SQLパフォーマンスUNION vs OR

最適化の記事の一部と、次のステートメントのsegfaultedを読みました。

ORUNIONを使用してSQL置換ステートメントを使用する場合:

select username from users where company = ‘bbc’ or company = ‘iTV’;

に:

select username from users where company = ‘bbc’ union
select username from users where company = ‘iTV’;

クイックEXPLAINから:

ORを使用:

enter image description here

UNIONを使用:

enter image description here

これは、UNION作業の2倍で行うことを意味しませんか?

UNIONは特定のRDBMSと特定のテーブルスキーマのパフォーマンスが向上する可能性があることに感謝していますが、これはcategorically trueではありません。

質問

私が間違っている?

56
Jason McCreary

あなたが読んだ記事が悪い例を使用したか、あなたが彼らの主張を誤解したかのどちらかです。

select username from users where company = 'bbc' or company = 'iTV';

これは次と同等です:

select username from users where company IN ('bbc', 'iTV');

MySQLは、このクエリに対してcompanyのインデックスをうまく使用できます。 UNIONを実行する必要はありません。

よりトリッキーなケースは、2つのdifferent列を含むOR条件がある場合です。

select username from users where company = 'bbc' or city = 'London';

companyにインデックスがあり、cityに別のインデックスがあるとします。 MySQLは通常、指定されたクエリのテーブルごとに1つのインデックスのみを使用するため、どのインデックスを使用する必要がありますか? companyのインデックスを使用する場合、cityがロンドンである行を見つけるためにテーブルスキャンを行う必要があります。 cityのインデックスを使用する場合、companyがbbcである行に対してテーブルスキャンを実行する必要があります。

UNIONソリューションは、このタイプのケース用です。

select username from users where company = 'bbc' 
union
select username from users where city = 'London';

これで、各サブクエリは検索にインデックスを使用でき、サブクエリの結果はUNIONによって結合されます。


匿名ユーザーが上記の私の回答の編集を提案しましたが、モデレーターが編集を拒否しました。編集ではなくコメントである必要があります。提案された編集の主張は、UNIONが結果セットをソートして重複行を排除する必要があるというものでした。これにより、クエリの実行が遅くなるため、インデックスの最適化に時間がかかります。

私の応答は、UNIONが発生する前に、インデックスが結果セットを少数の行に減らすのに役立つということです。 UNIONは実際に重複を排除しますが、それを行うには小さな結果セットをソートするだけです。 WHERE句がテーブルの重要な部分と一致する場合があり、UNION中のソートは、単にテーブルスキャンを実行するのと同じくらい高価です。しかし、インデックス付き検索によって結果セットが削減されるのがより一般的であるため、ソートはテーブルスキャンよりもはるかに低コストです。

違いは、テーブル内のデータと検索対象の用語によって異なります。特定のクエリに最適なソリューションを決定する唯一の方法は、両方のメソッドを MySQLクエリプロファイラ で試し、パフォーマンスを比較することです。

86
Bill Karwin

これらは同じクエリではありません。

私はMySQLの経験があまりないので、クエリオプティマイザーが何をするかしないかわかりませんが、ここに私の一般的な背景(主にms SQLサーバー)からの私の考えを示します。

通常、クエリアナライザーは上記の2つのクエリを取得し、それらからまったく同じ計画を作成できます(それらが同じ場合)。これらのクエリ(同等)の間にパフォーマンスの違いはないと思われます。

select distinct username from users where company = ‘bbc’ or company = ‘iTV’;

そして

select username from users where company = ‘bbc’ 
union
select username from users where company = ‘iTV’;

さて、問題は、実際にはわかりませんが、次のクエリには違いがありますが、オプティマイザは最初のクエリのようにすると思われます

select username from users where company = ‘bbc’ or company = ‘iTV’;

そして

select username from users where company = ‘bbc’ 
union all
select username from users where company = ‘iTV’;
5
Darren Kopp

これは、データのサイズ、インデックス、ソフトウェアバージョンなどに基づいてオプティマイザーが実行する処理に依存します。

ORを使用すると、すべてが単一の論理ステートメント内にあるため、オプティマイザーが効率を見つける可能性が高くなると思います。

また、UNIONには、リセットset(重複なし)が作成されるため、オーバーヘッドがあります。 companyがインデックス付けされている場合、UNIONの各ステートメントは非常に高速に実行されるはずです...実際に実行されているかどうかわからないdouble作品。

ボトムライン

クエリからすべての速度を絞る必要が本当にない限り、意図を最もよく伝えるフォームを使用することをお勧めします... OR

更新

INについても言及しました。次のクエリは、OR(これも私が好む形式です)よりも優れたパフォーマンスを提供すると信じています。

select username from users where company in ('bbc', 'iTV');

2
David J