web-dev-qa-db-ja.com

インデックススキャンのクエリパフォーマンスがPostgresの並列シーケンススキャンよりも遅い

AWS Aurora上のPostgreSQL 10でパフォーマンスの問題をデバッグしようとしています。

具体的には、バッファキャッシュにキャッシュページが含まれていない「コールド」クエリのパフォーマンスの問題を理解しようとしています。

インデックス付きのテーブルがあり、プランナがインデックスを使用する場合、クエリは大幅に遅くなります(IOで知ることができる時間が長くなります)。しかし、インデックスを削除すると、クエリはより高速で、並列シーケンススキャンを使用します。

テーブルのスキーマ:

CREATE TABLE max_test_2018_3
(
   timestamp_         timestamp,
   person_alias       varchar(128),
   visitor_id         varchar(128),
   session_id         varchar(24),
   page_title         varchar(1024),
   location_Host      varchar(256),
   location_path      varchar(1024),
   location_query     varchar(1024),
   location_fragment  varchar(1024),
   referrer_Host      varchar(256),
   referrer_path      varchar(1024),
   referrer_query     varchar(1024),
   referrer_fragment  varchar(1024),
   duration           integer,
   location_secure    boolean,
   referrer_secure    boolean,
   id                 uuid,
   person_id          uuid,
   custom_properties  jsonb
);

インデックスDDLは次のとおりです。

CREATE INDEX max_test_2018_3_ix   ON max_test_2018_3
  USING btree  ( location_path varchar_pattern_ops);

そしてクエリは:

explain (analyze, buffers)
SELECT O.person_id, 1 as step1, min(timestamp_) AS timestamp_ 
FROM max_test_2018_3 O
WHERE O.location_path  like '/tax-calculator%' 
GROUP BY O.person_id

次の2つの説明を確認してください。どちらの説明も、バッファヒットが最小限かまったくないことを示しています。 1つはインデックスを使用した実行を示し、もう1つはインデックスが削除された後の実行を示しています。

インデックスなし-> https://explain.depesz.com/s/N4uowith index-> https://explain.depesz.com/s/69WS

インデックススキャンを含むプランは193秒かかりますが、seqスキャンでは43秒かかります。 「With-index」プランのステップ2がなぜ遅いのですか。 118372バッファー(約118 MBのデータ)のみを読み取りますが、このステップには193秒かかりました。どうして?バッファキャッシュがウォームアップされると、同じwith-indexクエリに数秒かかります。したがって、IOがこの余分な時間の原因であることを認めなければなりません。

複数の類似したデータセットに対してこの実験を数回実行しました。 IOを必要とし、バッファキャッシュの恩恵を受けないインデックススキャン操作を示す別の例を次に示します。

インデックスなし-> https://explain.depesz.com/s/g6Jwith Index-> https://explain.depesz.com/s/Sw6Q

ここでも、インデックススキャンが不当に遅いことがわかります。プランナはクエリを高速化すると考えているため、インデックスを使用しようとしますが、そのようなクエリは常に低速です。

プランナーに影響を与えるパラメーターについて、次の2つを設定しました。

random_page_cost = 1    
seq_page_cost = 1 

SSDドライブの場合、random_page_costはシークを必要としないため、seq_page_costと同じ値に設定できます。

テーブルは最新の統計でバキュームされます。テーブルmax_test_2018_3には約1800万行が含まれ、ディスク上で約9GBです。そのテーブルの上記のインデックスは440 MBです。

インデックススキャンを使用するプランのパフォーマンスが低いのはなぜですか?

I/Oタイミングが有効なプラン

週間並列処理設定

上記の説明には、並列処理に関するデフォルトのパラメータ設定があります。唯一の2つの例外は次のとおりです。

max_parallel_workers = 8

max_parallel_workers_per_gather = 4

私が次の設定で実験した提案に従って:

parallel_setup_cost = 10

parallel_Tuple_cost = 0.001

これらのデフォルトは、それぞれ1000と0.1です。これらの変更は計画に影響を与えず、postgresは並列seqスキャンがより高速であってもインデックスを使用することを選択しました。

インデックスサイズは440MBで、デフォルトのmin_parallel_index_scan_sizeの512kBよりもはるかに大きい

2
maxTrialfire

すべての時間は、テーブルI/Oの実行に費やされます。これは、コールドキャッシュを使用したテストで予想されます。

インデックススキャンには時間がかかりますが、それは並列化されていないためです。順次スキャンはより多くの合計時間を使用しますが、5つのコアで並行して実行されるため、より速く終了します。

PostgreSQL v10 can並列インデックススキャンを実行するため、残りのなぞなぞがそうではありません。副次的な問題が、シーケンシャルスキャンが非常に多くの並列ワーカーを使用する理由です。

設定パラメータをごちゃごちゃにしたと思います。関連するパラメータは次のとおりです。

  • max_parallel_workers_per_gather:使用できるワーカーの数を制限します。これを4以上に設定しておく必要があります。

  • min_parallel_table_scan_size:テーブルがそれよりも大きい場合、並列ワーカーが計画されます。テーブルのサイズが3を超える場合n- 1 その値の倍、n並列ワーカーが計画されます。そのため、テーブルが非常に大きいか、パラメータを減らしました。または:

  • テーブルのストレージパラメータparallel_workersは、上記のようにmin_parallel_table_scan_sizeに基づく計算をオーバーライドするため、設定した可能性があります。

  • 最後に、min_parallel_index_scan_sizeは、並列インデックススキャンが考慮されるタイミングを管理します。インデックスが小さいか、パラメータを下げました。

これらのパラメータを適切な値に設定すると、インデックススキャンが高速になると思います。

1
Laurenz Albe