web-dev-qa-db-ja.com

ビットマップインデックススキャンを使用したクエリプランの「条件の再確認:」行

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

PostgreSQL 9.4を使用すると、EXPLAINによって出力されたクエリプランでビットマップインデックスがスキャンされた後、常にRecheck Cond:行が表示されます。

参照された質問の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))

これは、ビットマップインデックススキャン後にもう一度インデックス条件をチェックする必要があることを意味しますか?
EXPLAINの出力から他に何を学ぶことができますか?

23

として @ Chrisは参照された質問に正しくコメントしました

少し調べたところ、再チェック条件は常にEXPLAINに出力されているようですが、実際には、_work_mem_がビットマップに損失が生じるほど小さい場合にのみ実行されます。考え? http://www.postgresql.org/message-id/[email protected]

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

_Recheck Cond:_行は、ビットマップインデックススキャン用にalwaysです。基本的な EXPLAIN の出力では、それ以上はわかりません。質問の2番目の引用にあるように、_EXPLAIN ANALYZE_から追加情報を取得します。

_Heap Blocks: exact=693 lossy=3732
_

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

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

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

追加行_BUFFERS:_

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

_Buffers: shared hit=279 read=79
_

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

より多くのオプションがあります。 BUFFERSオプションに関するマニュアル:

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

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

18

アーウィン、これは以前からのコメントスレッドでの議論だったので、もう少し突っ込むことにしました...

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

SET work_mem = 64;

非常に小さいwork_memを設定し、

SET work_mem = default;

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

EXPLAIN&条件の再確認

したがって、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の場合のみ、予想どおり、クエリプランは再チェック条件が可能であることを示していますが、実際に計算されるかどうかはわかりません。

EXPLAIN ANALYZE&再確認条件

クエリに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ヒープブロックがあることがわかります。

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

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

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

10
Chris