web-dev-qa-db-ja.com

UNION ALL結果のフィルタリングは、各サブクエリのフィルタリングよりもはるかに遅くなります

edit:簡単な例については、終わりを参照してください)

「cases」という名前のテーブル(13.5万行、29列)を検索しています。このテーブルの一部の行には、(異なるタイプの)親子関係のタイプがあります。つまり、これらのレコードでは、フィルタリングと表示に親/子フィールドの混合を使用する必要があります。

4つの異なる親子関係を特定し、それらのビューを作成しました。

  • caselist_no_specials:子レコードではなく、レコードデータをそのまま使用します。合計116106行。
  • caselist_disputes_with_ipr:子レコード;合計138行。
  • caselist_mark_children:子レコード;合計18132行。
  • caselist_design_children:子レコード。合計671行。

これらのビューの結果は重複せず、テーブルの100%をカバーします。

それらすべての和集合を選択し、各ビューを個別にフィルタリングすると、クエリに約9ミリ秒かかります。すべてのビューの和集合を選択し、その結果をフィルタリングするには、約500ミリ秒かかります。

私はまた、ビューなしでこれをテストし、ビューに含まれるクエリをインライン化しましたが、測定可能な改善はありませんでした。

これは高速クエリです( explain ):

  SELECT  c.*
    FROM  caselist_no_specials c
    JOIN  case_clients cacl ON cacl.case_id = c.main_id
   WHERE  cacl.client_id = 12046

   UNION ALL

  SELECT  c.*
    FROM  caselist_disputes_with_ipr c
    JOIN  case_clients cacl ON cacl.case_id = c.main_id
   WHERE  cacl.client_id = 12046

   UNION ALL

  SELECT  c.*
    FROM  caselist_mark_children c
    JOIN  case_clients cacl ON cacl.case_id = c.main_id
   WHERE  cacl.client_id = 12046

   UNION ALL

  SELECT  c.*
    FROM  caselist_design_children c
    JOIN  case_clients cacl ON cacl.case_id = c.main_id
   WHERE  cacl.client_id = 12046

ORDER BY  sort_nr,
          id;

ご覧のとおり、結合とフィルタはビューごとに複製されています。重複を回避しようとすると、次のクエリが生成されます。これにはかなり時間がかかります( explain ):

  SELECT  x.*
    FROM  (
              SELECT * FROM caselist_no_specials
              UNION ALL
              SELECT * FROM caselist_disputes_with_ipr
              UNION ALL
              SELECT * FROM caselist_mark_children
              UNION ALL
              SELECT * FROM caselist_design_children
          ) x
    JOIN  case_clients cacl ON cacl.case_id = x.main_id
   WHERE  cacl.client_id = 12046
ORDER BY  x.sort_nr,
          x.id;

外部クエリのフィルタ/結合が内部サブクエリに適用できることをPostgreSQLに何らかの方法で知らせることは可能ですか?

または、各ビューを個別にフィルタリングしないようにする他の方法はありますか?このクエリのユーザー向けフォームには20を超えるフィルターフィールドがあり、最大14の追加テーブルを持つJOINが存在する可能性があります。

PostgreSQLはLinuxで実行されているバージョン9.4.7です。


EDIT:私は多くの 簡略化された例 を作成しました、3つのビューを使用して元のテーブルを単にパーティション化しますが、他のテーブルは関与しません(および クエリプラン の両方のバリアント)。振り返ってみると、これはそもそも例として使用すべきだったものです。

6
Zilk

クエリ1でDBに要求することは、次のとおりです。テーブルAからすべてを取得フィルター済みテーブルBからすべてを取得フィルター済みテーブルCからすべてを取得フィルター済みテーブルDからすべてを取得フィルター済み次にユニオン。

2番目のクエリでは、最初にすべてのデータを取得し、その後で初めて結合とフィルターを実行します。 UNIONクエリでのJOINとWHEREは、実際にはインデックスを作成できませんが、明らかに遅くなります。 (これは、サーバーバリアントやOSとは関係ありません)。

4
Hila DG

これらのビューの結果は重複せず、テーブルの100%をカバーします。

基になるテーブルをクエリするだけでは何ができませんか?最速である必要があります:

SELECT  x.*
FROM    cases x
JOIN    case_clients cacl ON cacl.case_id = x.main_id
WHERE   cacl.client_id = 12046
ORDER   BY x.sort_nr, x.id;
1