3

先日、クエリで問題が発生しました。大きなデータセットの場合、約 10 秒かかりました。クエリは次のようになります。

SELECT a.* from Document as a
LEFT JOIN Waybill as b on a.waybill = b.id
WHERE a.enterpriseGuid = '763a3ac3-a3c7-4379-9735-2a4a96e87e5d'
OR b.enterpriseGuid = '763a3ac3-a3c7-4379-9735-2a4a96e87e5d'

これはかなり遅くなりました。ただし、次のように変更しました。

SELECT a.* from Document as a
LEFT JOIN Waybill as b on a.waybill = b.id
WHERE a.enterpriseGuid = '763a3ac3-a3c7-4379-9735-2a4a96e87e5d'
UNION ALL
SELECT a.* from Document as a
LEFT JOIN Waybill as b on a.waybill = b.id
WHERE b.enterpriseGuid = '763a3ac3-a3c7-4379-9735-2a4a96e87e5d'

2 つのクエリは基本的に同じ結果を生成しますが、これには約 0.01 秒かかりました。MySQL の公式ドキュメントを探したところ、興味深いコメントが見つかりまし

インデックスは、OR 状況で使用すると速度の利点を失います (4.1.10):

SELECT * FROM a WHERE index1 = 'foo' UNION SELECT * FROM a WHERE index2 = 'baar';

よりもはるかに高速です

SELECT * FROM a WHERE index1 = 'foo' OR index2 = 'bar';

だから、私の質問には3つの部分があります:

  • 本番システム (つまり、データセットが非常に大きい場合) で選択クエリで OR 句を使用するのは本当に悪いことですか?
  • この OR クエリは、何らかの方法でインデックスによって調整できますか? 現在、フィルター処理に使用するクエリの両方の列が実際にインデックス化されています。OR を UNION ALL と同じくらい高速に動作させるために、複雑な複合インデックスを作成できますか?
  • これはベンダー固有の問題ですか、それとも Oracle や Postgresql でも同じ問題が発生するのでしょうか?
4

2 に答える 2

2

ORそれ自体は悪くありません。SQL の他のほとんどすべての構造と同様に、これは良い考えかもしれませんし、そうでないかもしれません。

オプティマイザーに問題が見つかりました。. . そして、多くのデータベースに共通するものです。OR条件が異なるテーブルからのものである場合、オプティマイザーがインデックスを利用することは非常に困難です。

各サブクエリがインデックスを利用できるため、改善されたソリューションが機能します。

次のバージョンは、最初のバージョンよりはうまく機能しますが、2 番目のバージョンよりは悪いことに気付くかもしれません。

SELECT d.*
FROM Document d
WHERE d.enterpriseGuid = '763a3ac3-a3c7-4379-9735-2a4a96e87e5d' OR
      (EXISTS (SELECT 1
               FROM Waybill b
               WHERE d.waybill = b.id AND
                     b.enterpriseGuid = '763a3ac3-a3c7-4379-9735-2a4a96e87e5d'
              )
      );
于 2015-10-02T11:23:08.363 に答える