ただし、この例では、最初のクエリの列a
に条件があります。 、一方、2番目のクエリには列b
の条件があります 。これはおそらく、最適化するのが難しいクエリから来たものです:
SELECT * FROM mytable WHERE a=X OR b=Y
このクエリは、単純なBツリーインデックスで最適化するのは困難です。エンジンは列a
のインデックスを検索しますか ?または列b
?いずれにせよ、他の用語を検索するには、テーブルスキャンが必要です。
したがって、UNIONを使用して、それぞれ1つの用語に対して2つのクエリに分割するトリック。各サブクエリは、各検索語に最適なインデックスを使用できます。次に、UNIONを使用して結果を結合します。
ただし、b=Y
の行があるため、2つのサブセットが重複する可能性があります。 a=X
もあります その場合、そのような行は両方のサブセットで発生します。したがって、重複した削除を行う必要があります。そうしないと、最終結果にいくつかの行が2回表示されます。
SELECT * FROM mytable WHERE a=X
UNION DISTINCT
SELECT * FROM mytable WHERE b=Y
UNION DISTINCT
通常の実装では行を並べ替えて重複を見つけるため、コストがかかります。 SELECT DISTINCT ...
を使用する場合と同じように 。
また、結合している行の2つのサブセットに、両方のサブセットで多数の行が発生している場合は、さらに「無駄な」作業になるという認識もあります。削除する行がたくさんあります。
ただし、2セットの行がすでに区別されていることを保証できる場合は、重複を排除する必要はありません。つまり、重複がないことを保証する場合です。これに頼ることができれば、重複を排除することは常にノーオペレーションであるため、クエリはそのステップをスキップできるため、コストのかかる並べ替えをスキップできます。
重複しない行のサブセットを選択することが保証されるようにクエリを変更すると、それがメリットになります。
SELECT * FROM mytable WHERE a=X
UNION ALL
SELECT * FROM mytable WHERE b=Y AND a!=X
これらの2つのセットには、重複がないことが保証されています。最初のセットにa=X
の行がある場合 2番目のセットにはa!=X
の行があります その場合、両方のセットに行が存在することはできません。
したがって、2番目のクエリは一部のみをキャッチします b=Y
である行の 、ただし、a=X AND b=Y
である任意の行 すでに最初のセットに含まれています。
したがって、クエリは2つのOR
の最適化された検索を実現します 用語、重複を生成せず、UNION DISTINCT
を必要としません 操作。