75

最適化の記事の一部を読んだところ、次のステートメントでセグメンテーション違反が発生しました。

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

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:

ここに画像の説明を入力

使用UNION:

ここに画像の説明を入力

UNIONこれは仕事が2倍になるということではないですか?

UNION特定の RDBMS と特定のテーブル スキーマではパフォーマンスが向上する可能性があることは理解していますが、これは著者が示唆するように完全に当てはまるわけではありません。

質問

私が間違っている?

4

5 に答える 5

131

あなたが読んだ記事は悪い例を使っていたか、またはそれらのポイントを誤解していました。

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

これは次と同等です。

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

companyMySQL は、このクエリにインデックスを使用できます。UNION を行う必要はありません。

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

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

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

解決策は、このUNIONタイプのケースです。

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

これで、各サブクエリは検索にインデックスを使用できるようになり、サブクエリの結果はUNION.


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

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

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

于 2012-12-13T18:35:40.000 に答える
5

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

私は 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’;
于 2012-12-06T19:07:19.260 に答える
2

データ、インデックス、ソフトウェアのバージョンなどのサイズに基づいて、オプティマイザが最終的に何をするかによって異なります。

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

また、UNION はリセットセットを作成するため(重複なし)、いくらかのオーバーヘッドがあります。会社がインデックス化されている場合、UNIONの各ステートメントはかなり迅速に実行されるはずです...実際に2倍の作業を行っているかどうかはわかりません。

結論

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

アップデート

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

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

于 2012-12-06T19:07:25.140 に答える
-1

ほとんどの場合、unionまたはunion allバージョンは users テーブルの 2 つのフル テーブル スキャンを実行します。

このorバージョンは、テーブルを 1 回だけスキャンするため、実際にははるかに優れています。また、使用可能な場合は、インデックスを 1 回だけ使用します。

元のステートメントは、ほぼすべてのデータベースと状況で間違っているようです。

于 2012-12-06T21:38:52.313 に答える