(edit:簡単な例については、終わりを参照してください)
「cases」という名前のテーブル(13.5万行、29列)を検索しています。このテーブルの一部の行には、(異なるタイプの)親子関係のタイプがあります。つまり、これらのレコードでは、フィルタリングと表示に親/子フィールドの混合を使用する必要があります。
4つの異なる親子関係を特定し、それらのビューを作成しました。
これらのビューの結果は重複せず、テーブルの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つのビューを使用して元のテーブルを単にパーティション化しますが、他のテーブルは関与しません(および クエリプラン の両方のバリアント)。振り返ってみると、これはそもそも例として使用すべきだったものです。
クエリ1でDBに要求することは、次のとおりです。テーブルAからすべてを取得フィルター済みテーブルBからすべてを取得フィルター済みテーブルCからすべてを取得フィルター済みテーブルDからすべてを取得フィルター済み次にユニオン。
2番目のクエリでは、最初にすべてのデータを取得し、その後で初めて結合とフィルターを実行します。 UNIONクエリでのJOINとWHEREは、実際にはインデックスを作成できませんが、明らかに遅くなります。 (これは、サーバーバリアントやOSとは関係ありません)。
これらのビューの結果は重複せず、テーブルの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;