私はPostgreSQL 9.4にこのテーブルを持っています:
CREATE TABLE user_operations(
id SERIAL PRIMARY KEY,
operation_id integer,
user_id integer )
テーブルは、すべてのユーザーのセットS
の一部のサブセット(それぞれ約~1000-2000
要素で構成される)に対応する80000-120000
異なる操作で構成されています。
S = {1, 2, 3, ... , 122655}
パラメーター:
work_mem = 128MB
table_size = 880MB
operation_id
にもインデックスがあります。
QUESTION:user_id
セットの重要な部分についてすべての異なるoperation_id
をクエリするための最適な計画は何ですか(20% -60%)のように:
SELECT DISTINCT user_id FROM user_operation WHERE operation_id < 500
テーブルにさらにインデックスを作成することは可能です。現在、クエリの計画は次のとおりです。
HashAggregate (cost=196173.56..196347.14 rows=17358 width=4) (actual time=1227.408..1359.947 rows=598336 loops=1)
-> Bitmap Heap Scan on user_operation (cost=46392.24..189978.17 rows=2478155 width=4) (actual time=233.163..611.182 rows=2518122 loops=1)
Recheck Cond: (operation_id < 500)
-> Bitmap Index Scan on idx (cost=0.00..45772.70 rows=2478155 width=0) (actual time=230.432..230.432 rows=2518122 loops=1)
Index Cond: (operation_id < 500)
このようなクエリプランは、このような状況で本当に最適ですか?つまり、Bitmap Heap Scan
を使用することの正確さについてはわかりません。私は関連する記事への参照に感謝します。
user_id
セット(20%〜60%)の重要な部分について、すべての個別のoperation_id
をクエリするための最適な計画はどれですか。
再帰クエリを使用します。
WITH RECURSIVE cte AS (
( -- parentheses are required
SELECT user_id
FROM user_operations
WHERE operation_id < 500
ORDER BY user_id
LIMIT 1
)
UNION ALL
SELECT u.user_id
FROM cte, LATERAL (
SELECT user_id
FROM user_operations
WHERE operation_id < 500
AND user_id > cte.user_id -- lateral reference
ORDER BY user_id
LIMIT 1
) u
)
TABLE cte;
(user_id, operation_id)
のインデックスとの組み合わせ-列の順序。 2番目の列でフィルター処理するインデックススキャンを期待しています。適度に正確なテーブル統計は重要なので、Postgresは次のuser_id
を見つけるためにインデックス内の数行をスキップするだけでよいことを認識しています。一般に、1つのmightは、特にoperation_id
の統計ターゲットを増やしたいと考えています。
ALTER TABLE user_operations ALTER operation_id SET STATISTICS 1000;
~1000-2000 different operations
しかないので、これは必要ないかもしれませんが、支払うのは少額です。
詳細:
If述語operation_id < 500
が安定している場合(常に同じ)、代わりに(user_id)
のみの部分インデックスを作成します。
CREATE INDEX foo ON user_operations (user_id) WHERE operation_id < 500;
その場合、operation_id
の統計は、このクエリに関連しなくなります。
述語が安定していない場合でも、可能な条件と値の頻度の全範囲に応じて、最適化する方法がある場合があります。
パフォーマンスは...deliciousである必要があります。
私はSO(詳細な説明付き)に関するこの関連する回答でテクニックを最適化しました:
If別のusers
テーブルがあり、すべてのユーザーの大部分がサンプルに含まれている場合、より高速なクエリスタイルが可能です。リンクされた回答の詳細。