ビットマップインデックススキャンを使用するクエリプランの「Recheck Cond:」行


21

これは、コメントから前の質問へのスピンオフです。

PostgreSQL 9.4を使用すると、Recheck Cond:によるクエリプラン出力でビットマップインデックススキャンの後に常に行があるように見えますEXPLAIN

EXPLAIN参照された質問の出力のように:

->  Bitmap Heap Scan on table_three  (cost=2446.92..19686.74 rows=8159 width=7)
      Recheck Cond: (("timestamp" > (now() - '30 days'::interval)) AND (client_id > 0))
      ->  BitmapAnd  (cost=2446.92..2446.92 rows=8159 width=0)
            ->  Bitmap Index Scan on table_one_timestamp_idx  (cost=0.00..1040.00 rows=79941 width=0)
                  Index Cond: ("timestamp" > (now() - '30 days'::interval))
            ->  Bitmap Index Scan on fki_table_three_client_id  (cost=0.00..1406.05 rows=107978 width=0)
                  Index Cond: (client_id > 0)

またはEXPLAIN ANALYZE、シンプルで巨大なテーブルの出力(非常に少ないwork_mem):

EXPLAIN ANALYZE SELECT * FROM aa WHERE a BETWEEN 100000 AND 200000;
Bitmap Heap Scan on aa  (cost=107.68..4818.05 rows=5000 width=4) (actual time=27.629..213.606 rows=100001 loops=1)
  Recheck Cond: ((a >= 100000) AND (a <= 200000))
  Rows Removed by Index Recheck: 758222
  Heap Blocks: exact=693 lossy=3732
  ->  Bitmap Index Scan on aai  (cost=0.00..106.43 rows=5000 width=0) (actual time=27.265..27.265 rows=100001 loops=1)
        Index Cond: ((a >= 100000) AND (a <= 200000))

それは、ビットマップインデックススキャン後に2回目にインデックス条件をチェックする必要があるということですか?出力
から他に何を学ぶことができEXPLAINますか?

回答:


17

@クリスは、参照、質問に正しくコメント

少し調べてみると、再チェック条件は常にに出力されているように見えますが、EXPLAIN実際にwork_memはビットマップが損失するほど小さい場合にのみ実行され ます。考え? http://www.postgresql.org/message-id/464F3C5D.2000700@enterprisedb.com

これはすべて真実であり、コア開発者のHeikki Linnakangasは一流のソースですが、投稿は2007年(Postgres 8.2)に遡ります。以下は、Michael PaquierによるPostgres 9.4の詳細な説明を含むブログ投稿です。ここでは、EXPLAIN ANALYZEより多くの情報で出力が改善されています。

Recheck Cond:ラインは、常にビットマップインデックススキャンのためにそこに。basicの出力では、EXPLAINそれ以上はわかりません。EXPLAIN ANALYZE質問の2番目の引用に見られるように、追加情報を取得します。

Heap Blocks: exact=693 lossy=3732

合計4425個のデータページ(ブロック)から、693個がタプル(タプルポインターを含む)を正確に保存しましたが、他の3732ページはビットマップで(データページのみ)損失がありました。これwork_memは、インデックススキャンから構築されたビットマップ全体を正確に(損失なしで)保存するのに十分な大きさでない場合に発生します。

ビットマップはフェッチするページのみを記憶し、ページ上の正確なタプルは記憶しないため、非可逆共有のページのインデックス条件を再確認する必要があります。ページ上のすべてのタプルが必ずしもインデックス条件を渡すわけではありません。実際に条件を再確認する必要があります。

これは、新しい追加について説明したpgsqlハッカースレッドです。著者の藤田work_mem Et郎は、損失のあるビットマップエントリとその後の条件の再チェックを回避するための最小値の計算方法の公式提供しています。計算は、複数のビットマップスキャンを使用する複雑なケースでは信頼性が低いため、実際の数値をから出力するために使用されませんでしたEXPLAIN。それでも、単純なケースの推定値として使用できます。

追加行 BUFFERS:

さらに、BUFFERSオプションを指定して実行すると、次のEXPLAIN (ANALYZE, BUFFERS) ...ような行が追加されます。

Buffers: shared hit=279 read=79

これは、キャッシュから読み込まれた基礎となるテーブル(およびインデックス)のshared hit=279量()およびディスクからフェッチされた量()を示しますread=79。クエリを繰り返した場合、通常、最初の呼び出し後にすべてがキャッシュされるため、「読み取り」部分はあまり大きくないクエリでは表示されません。最初の呼び出しは、すでにキャッシュされている量を示します。後続の呼び出しは、キャッシュがどれだけ処理できるかを示します(現在)。

さらにオプションがあります。オプションに関するマニュアルBUFFERS

具体的には、ヒット、読み取り、ダーティ、および書き込みの共有ブロックの数、ヒット、読み取り、ダーティ、および書き込みのローカルブロックの数、および読み取りと書き込みの一時ブロックの数を含めます。

続きを読む、もっとあります。ソースコードの
出力オプションのリストを次に示します


10

アーウィン、これは以前のコメントスレッドでの議論だったので、もう少し詳しく調べることにしました...

適切なサイズのテーブルからの非常に単純なクエリがあります。通常は十分work_memですが、この場合はコマンドを使用しました

SET work_mem = 64;

非常に小さなを設定するwork_memと、

SET work_mem = default;

work_memクエリに十分な大きさになるように設定します。

条件の説明と再確認

だから、唯一と私のクエリを実行しているEXPLAINとして、

EXPLAIN 
SELECT * FROM olap.reading_facts
WHERE meter < 20;

私は低と高の両方の結果を得ましたwork_mem

低い work_mem

Bitmap Heap Scan on reading_facts  (cost=898.92..85632.60 rows=47804 width=32)
  Recheck Cond: (meter < 20)
  ->  Bitmap Index Scan on idx_meter_reading_facts  (cost=0.00..886.96 rows=47804 width=0)
        Index Cond: (meter < 20)

高い work_mem

Bitmap Heap Scan on reading_facts  (cost=898.92..85632.60 rows=47804 width=32)
  Recheck Cond: (meter < 20)
  ->  Bitmap Index Scan on idx_meter_reading_facts  (cost=0.00..886.96 rows=47804 width=0)
        Index Cond: (meter < 20)

長い話ですEXPLAINが、予想どおり、クエリプランは再チェック条件が可能であることを示していますが、実際に計算されるかどうかはわかりません。

分析の説明と条件の再確認

ANALYZEクエリに含めると、結果から、知っておくべきことがさらにわかります。

低い work_mem

Bitmap Heap Scan on reading_facts  (cost=898.92..85632.60 rows=47804 width=32) (actual time=3.130..13.946 rows=51840 loops=1)
  Recheck Cond: (meter < 20)
  Rows Removed by Index Recheck: 86727
  Heap Blocks: exact=598 lossy=836
  ->  Bitmap Index Scan on idx_meter_reading_facts  (cost=0.00..886.96 rows=47804 width=0) (actual time=3.066..3.066 rows=51840 loops=1)
        Index Cond: (meter < 20)

高い work_mem

Bitmap Heap Scan on reading_facts  (cost=898.92..85632.60 rows=47804 width=32) (actual time=2.647..7.247 rows=51840 loops=1)
  Recheck Cond: (meter < 20)
  Heap Blocks: exact=1434
  ->  Bitmap Index Scan on idx_meter_reading_facts  (cost=0.00..886.96 rows=47804 width=0) (actual time=2.496..2.496 rows=51840 loops=1)
        Index Cond: (meter < 20)

繰り返しになりますが、予想どおり、これらを含めることでANALYZE、非常に重要な情報が明らかになります。低いwork_memケースでは、インデックスの再チェックによって削除された行があり、lossyヒープブロックがあることがわかります。

結論?(またはその欠如)

残念ながら、ビットマップヒープスキャン中にページを保持するために行IDの一部が削除されているため、インデックスの再確認が実際に必要かどうかを判断するEXPLAINだけでは不十分のようです。

EXPLAIN ANALYZE中程度の長さのクエリの問題を診断するには、使用することで問題ありませんが、クエリの完了に非常に長い時間がかかる場合EXPLAIN ANALYZE、ビットマップインデックスが不十分でwork_memあるために損失の多いものに変換されていることを発見するために実行することは、依然として難しい制約です。EXPLAINテーブル統計からこの発生の可能性を推定する方法があればいいのにと思います。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.