問題を特定する方法
実行計画を上から下に読んで問題点を特定する
実行計画を上から下に読み、時間のかかる演算子を確認して分析します。
実行コストを確認し、行数を比較する
実行コストの推定値が非常に高いか低いかを確認し、推定された行を実際に実行された行と比較して問題を特定します。
時間のかかるオペレーターには注意してください
NestLoopやSortとGroupByAggの組み合わせなどの演算子は、分析処理シナリオではほとんど必要ないため、注意してください。
特定の演算子をチェックする
不要なモーション演算子をチェックします。 モーション演算子を減らすために配布キーを最適化できるかどうか、および複製されたテーブルにモーション演算子を使用できるかどうかを確認します。
内側と外側のテーブルが適切な順序で結合されているかどうかを確認します。
インデックスとパーティションテーブルにスキャン演算子を使用できるかどうかを確認します。
メモリ情報に基づいてパラメータを調整する
ディスクへの一時的なスピルファイルを照会して分析します。 次に、statement_memパラメーターを適切な値に調整します。
例:
Update (cost=0.00..1274.11 rows=1 width=1) (actual time=995096.707..1517097.191 rows=245136 loops=1)
Executor Memory: 1kB Segments: 96 Max: 1kB (segment 0)
-> Partition Selector for t2 (cost=0.00..1274.04 rows=1 width=842) (actual time=995096.480..1514408.806 rows=245136 loops=1)
-> Redistribute Motion 96:96 (slice2; segments: 96) (cost=0.00..1274.04 rows=1 width=838) (actual time=995096.440..1513830.155 rows=245136 loops=1)
Hash Key: t2.c1, t2.c2
-> Split (cost=0.00..1274.04 rows=1 width=838) (actual time=995080.103..1496878.037 rows=245136 loops=1)
Executor Memory: 1kB Segments: 96 Max: 1kB (segment 0)
-> Hash Join (cost=0.00..1274.04 rows=1 width=1484) (actual time=995080.071..1496625.817 rows=122568 loops=1)
Hash Cond: ((t1.c1)::text = (t2.c1)::text)
Executor Memory: 33535270kB Segments: 96 Max: 349326kB (segment 33)
work_mem: 33535270kB Segments: 96 Max: 349326kB (segment 33) Workfile: (96 spilling)
Work_mem wanted: 26684983K bytes avg, 26684983K bytes max (seg0) to lessen workfile I/O affecting 96 workers.
-> Seq Scan on t1 (cost=0.00..672.28 rows=121412 width=736) (actual time=672.771..1039.167 rows=122568 loops=1)
Filter: ((t1.c2 = '2019-05-17'::date) AND ((t1.c3)::text = '0'::text))
-> Hash (cost=431.00..431.00 rows=1 width=762) (actual time=994417.443..994417.443 rows=34583155 loops=1)
-> Broadcast Motion 96:96 (slice1; segments: 96) (cost=0.00..431.00 rows=1 width=762) (actual time=25.562..912862.203 rows=34583155 loops=1)
-> Sequence (cost=0.00..431.00 rows=1 width=762) (actual time=34.475..4822.173 rows=361460 loops=1)
-> Partition Selector for t2 (dynamic scan id: 1) (cost=10.00..100.00 rows=2 width=4) (never executed)
Partitions selected: 27 (out of 27)
-> Dynamic Seq Scan on t2 (dynamic scan id: 1) (cost=0.00..431.00 rows=1 width=762) (actual time=34.441..4680.938 rows=361460 loops=1)
Partitions scanned: Avg 27.0 (out of 27) x 96 workers. Max 27 parts (seg0).上記の例は、SQL文に対してEXPLAIN ANALYZEを実行した実行計画を示しています。 上記の方法を使用して問題を特定できます。
実行計画を上から下に読み、各オペレータが実際に消費した時間を確認します。 ハッシュ結合は、完了するのに最も長い時間を要する。
次のハッシュ結合情報は、内部テーブルデータがディスクにスピルされていることを示しています。
「work_mem: 33535270kBセグメント: 96最大: 349326kB (セグメント33) ワークファイル: (96スピル) Work_memが必要: 26684983Kバイトavg、26684983KバイトMax (seg0) 96ワーカーに影響するワークファイルI/Oを減らします。」以下の情報は、ハッシュ結合に関与する内部テーブルがビルド段階でブロードキャストモーションを有することを示す。
「ブロードキャストモーション96:96 (スライス1; セグメント: 96) (コスト=0.00 .. 431.00行=1幅=762) (実際の時間=25.562 .. 912862.203行=34583155ループ=1) 」。 オプティマイザは、t1テーブルに1つの行があると推定しますが、これは実際の状況とは異なります。上記の診断結果は、t1テーブルでのタイムリーな統計収集がないため、オプティマイザがt2テーブルを小さなテーブルと見なしていることを示しています。 オプティマイザは、ハッシュ結合中にt2テーブルをすべてのノードにブロードキャストし、t2テーブルを内部テーブルとして使用することによってハッシュテーブルを構築します。 その結果、t2テーブルデータがディスクにこぼれ、SQL文が完了するまでに長い時間がかかります。
上記の問題を解決するには、ANALYZE t2; ステートメントを実行して、t2テーブルの統計を再度収集します。