web-dev-qa-db-ja.com

group byの既にクラスター化されたインデックスでの並べ替えを回避する

2つのフィールドTpidを持つテーブルdidでは、次のクエリの結果はseqになります。スキャンし、次にpidをソートします。

select count(did), pid 
from  T
group by pid

クエリプランは次のとおりです。

GroupAggregate  (cost=21566127.88..22326004.09 rows=987621 width=8)
->  Sort  (cost=21566127.88..21816127.88 rows=100000000 width=8)
    Sort Key: pid
     ->  Seq Scan on tc  (cost=0.00..1442478.00 rows=100000000 width=8)

ただし、テーブルには既にpidのクラスター化インデックスがあります。

なぜPostgresは単にテーブルをスキャンしてグループを計算しないのですか?なぜ再度pidでソートする必要があるのですか?

Postgresにグループのクラスター化インデックスを強制的に使用させるにはどうすればよいですか?

4
Sandeep

WHERE句がないため、集計を計算するには、テーブル全体をスキャンする必要があります(クエリ)。すべてのデータを取得したら、インデックスに移動して行を照合し、それらを順番に返すよりも、直接ソートする方がはるかに簡単です。この後者は、メモリでの操作と比較して遅い追加のI/Oを伴います。

If PostgreSQL 9.2(またはそれ以上)を使用していたand(pid, did)にインデックスを作成した場合、オプティマイザmightがインデックスを選択した代わりにスキャンしてください。

3
dezso

(@dezsoの回答について詳しく説明します。これは、この回答よりも優先して受け入れられるべきものです):

ただし、テーブルには既にpidのクラスター化インデックスがあります。

いいえ、そうではありません。PostgreSQL(9.3以降では)にはクラスター化インデックス(他の一部のDBベンダーの言語では「インデックス指向のテーブル」)がないためです。 PostgreSQLのすべてのテーブルは、セカンダリインデックスを持つヒープです。

インデックスでCLUSTERを実行して、インデックスに従ってヒープをソートできますが、これは一度だけです。 Pgはその後の更新/挿入でその順序を維持しようとしないため、テーブルがその順序であることに依存することはできません。 the docs を参照してください:

「テーブルがCLUSTERedになると、インデックス情報に基づいて物理的に並べ替えられます。クラスタリングは1回限りの操作です。その後、テーブルが更新されても、変更はクラスタリングされません。つまり、試行は行われません。新規または更新された行を、インデックスの順序に従って格納します。」

Pgがインデックスのみのテーブルに提供する最も近いものは、9.2以上でのセカンダリインデックスに対するインデックスのみのスキャンのサポートです。 (pid, did)およびにインデックスがあった場合、可視性マップは十分に堅固でした(つまり、チャーン率が高すぎず、自動バキュームが十分頻繁に実行されている) )次に、PGは index-only scan を実行することを選択する場合があります。セカンダリインデックスからほとんどのデータをフェッチし、可視性情報をチェックする必要がある少数の行のヒープにのみ行きます。

したがって:9.2にアップグレードし、(pid, did)にインデックスを作成することを検討してください。

1
Craig Ringer