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です。
インデックススキャンを使用するプランのパフォーマンスが低いのはなぜですか?
上記の説明には、並列処理に関するデフォルトのパラメータ設定があります。唯一の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よりもはるかに大きい
すべての時間は、テーブル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
は、並列インデックススキャンが考慮されるタイミングを管理します。インデックスが小さいか、パラメータを下げました。
これらのパラメータを適切な値に設定すると、インデックススキャンが高速になると思います。