5

Postgres 9.1 を使用していますが、クエリの実行が非常に遅いです。

クエリ:

Explain Analyze SELECT COUNT(DISTINCT email) FROM "invites" WHERE (
 created_at < '2012-10-10 21:08:05.259200'
 AND invite_method = 'email' 
 AND accept_count = 0 
 AND reminded_count < 3 
 AND (last_reminded_at IS NULL OR last_reminded_at < '2012-10-10 21:08:05.261483'))

結果:

Aggregate  (cost=19828.24..19828.25 rows=1 width=21) (actual time=11395.903..11395.903 rows=1 loops=1)
  ->  Seq Scan on invites  (cost=0.00..18970.57 rows=343068 width=21) (actual time=0.036..353.121 rows=337143 loops=1)
        Filter: ((created_at < '2012-10-10 21:08:05.2592'::timestamp without time zone) AND (reminded_count < 3) AND ((last_reminded_at IS NULL) OR (last_reminded_at < '2012-10-10 21:08:05.261483'::timestamp without time zone)) AND ((invite_method)::text = 'email'::text) AND (accept_count = 0))
Total runtime: 11395.970 ms

ご覧のとおり、これには約 11 秒かかります。このクエリのパフォーマンスを最適化するためにインデックスを追加するにはどうすればよいですか?

4

2 に答える 2

7

ジムがアドバイスするように「すべて」を単に索引付けすることは、あまり効率的な戦略ではありません。インデックスには維持コストがかかり、多くの個々のインデックスを組み合わせることは、1 つの調整されたインデックスよりも (維持およびクエリに) コストがかかります。それは常にあなたの完全な状況に依存します。

インデックスのコストは、読み取り専用またはほとんど書き込まれないテーブルでは低くなりますが、書き込み操作が多い揮発性のテーブルでは高くなります。追加の欠点は、関連する列を変更する HOT-Update (ヒープのみのタプル) がインデックスによって禁止されることです。見る:

特定のクエリのパフォーマンスが重要な場合は、部分的な複数列インデックスを使用することをお勧めします。特殊化されていますが、関連するすべての列の個々のインデックスよりもはるかに安価で高速です。経験則は...

  • 不安定な条件 (クエリ間で異なる) の列をインデックスに入れます。
  • 句で安定した条件 (すべてのクエリで同じ) を使用してWHERE、インデックスのパーティションを絞り込みます。

列名から判断すると(情報が不足しているため)、accept_count = 0ここで最も選択的な(そして安定した)フィルターのようですが、created_atおそらくlast_reminded_at変化し続けています。だから多分このようなもの:

CREATE INDEX invites_special_idx
ON     invites (created_at, last_reminded_at)
WHERE  accept_count = 0
AND    invite_method = 'email'
AND    reminded_count < 3;

クエリに完全に一致するように並べ替えcreated_atlast_reminded_at 昇順- とにかくデフォルトです。このようにして、システムはインデックスの先頭から 1 回のスキャンで関連するすべての行を取得できます。非常に高速である必要があります。

以前の質問の 1 つで説明したように、インデックスでテーブルをクラスター化するとさらに役立つ場合があります。についての説明書を必ずお読みくださいCLUSTER。@Craig が提供したように、部分インデックスで
はできません。CLUSTERこれCLUSTERは 1 回限りの操作であるため (後で書き込み操作を行うと効果が低下します)、完全なインデックス、CLUSTERテーブルを作成し、インデックスを再度削除することで、この制限を回避できます。お気に入り:

CREATE INDEX invites_special_idx2 ON invites (created_at, last_reminded_at);
CLUSTER invites USING invites_special_idx2;
DROP INDEX invites_special_idx2;

CLUSTERデータ分散の要件が相反する重要なクエリが他にない場合にのみ役立ちます。

PostgreSQL 9.2 には、クエリを高速化するいくつかの新機能があります。特に、インデックスのみのスキャン (リリース ノートの最初の項目)。アップグレードを検討してください。

于 2012-10-16T23:15:48.387 に答える
0

email、created_at、invite_method、accept_count、remended_count、および last_remided のインデックスを追加する必要があります。通常、WHERE ステートメントの左側にあるもの。

于 2012-10-16T22:21:07.163 に答える