質問
3つのインデックスを持つ2億5000万行を含むテーブルでUPDATEを実行しています。このUPDATEは、3000万行を含む別のテーブルを使用します。約36時間実行されています。彼らがそれをするのに100万日かかるとしたら、それがどれほど近いかを知る方法なのだろうかと思っています。まだ1〜2日しか必要ない場合は、実行させます。コマンドクエリは次のとおりです。
UPDATE pagelinks SET pl_to = page_id
FROM page
WHERE
(pl_namespace, pl_title) = (page_namespace, page_title)
AND
page_is_redirect = 0
;
ここではEXPLAINは問題ではなく、UPDATEにかかる時間をいくぶん正当化するために、大きなテーブルに複数のインデックスがあることだけに言及します。とにかくここに説明があります:
Merge Join (cost=127710692.21..135714045.43 rows=452882848 width=57)
Merge Cond: (("outer".page_namespace = "inner".pl_namespace) AND ("outer"."?column4?" = "inner"."?column5?"))
-> Sort (cost=3193335.39..3219544.38 rows=10483593 width=41)
Sort Key: page.page_namespace, (page.page_title)::text
-> Seq Scan on page (cost=0.00..439678.01 rows=10483593 width=41)
Filter: (page_is_redirect = 0::numeric)
-> Sort (cost=124517356.82..125285665.74 rows=307323566 width=46)
Sort Key: pagelinks.pl_namespace, (pagelinks.pl_title)::text"
-> Seq Scan on pagelinks (cost=0.00..6169460.66 rows=307323566 width=46)
pagelinks 'インデックスの1つを削除するために、並列クエリコマンドも送信しました。もちろん、UPDATEが終了するのを待っています(しかし、とにかく試してみたいと思いました!)。したがって、データの破損を恐れて pagelinks から何も選択することはできません(DROP INDEXポストマスタープロセスを終了しても安全だと思わない限り)。
だから、それらがデッドタプルの量や何かを追跡するテーブルかどうか疑問に思っています。UPDATEがタスクの完了にどれくらいの速さまたはどれくらいの距離があるかを知ることは素晴らしいことです。
Thx (PostgreSQLは思ったほどインテリジェントではありません。ヒューリスティックが必要です)
解決
" EXPLAINの使用に関するPostgreSQLドキュメントを読みましたか&quot ;、表示している出力を解釈しますか?
私は通常のPostgreSQLユーザーではありませんが、そのドキュメントを読み、表示されている EXPLAIN
出力と比較しました。 UPDATE
クエリはインデックスを使用していないようで、 page
と pagelinks
の両方をソートするためにテーブルスキャンを実行する必要があります。ソートは一時ディスクファイルを必要とするのに十分な大きさであることは間違いありません。一時ディスクファイルは temp_tablespace
の下に作成されると思います。
その後、推定データベースページが表示されます。その EXPLAIN
出力の最上位には(cost = 127710692.21..135714045.43)
と表示されます。ここでのユニットは、ディスクI / Oアクセスにあります。したがって、この UPDATE
を実行するために、1億3500万回以上ディスクにアクセスします。
シーク時間が5msの10,000rpmのディスクでも、最適な条件下で最高で毎秒200回のI / O操作を達成できます。これは、その期間中に飽和したディスクI / Oを維持できる場合でも、 UPDATE
が188時間(7.8日)のディスクI / Oを要することを意味します(つまり、中断なしで連続読み取り/書き込み) 。これは不可能であり、特にその間このサーバーをあらゆる種類の作業に使用していることは間違いないため、実際のスループットは少なくとも1桁はオフになると予想しています。したがって、あなたは UPDATE
のほんの一部に過ぎないと思います。
私なら、最初の日にこのクエリを強制終了し、インデックスをより有効に活用し、ディスク上のソートを必要としない UPDATE
を実行する別の方法を見つけました。おそらく、1つのSQLステートメントでそれを行うことはできません。
DROP INDEX
に関しては、単にブロックし、テーブルへの排他的アクセスを待っていると思います。この状態になっている間は、おそらくそれを殺すことができると思います。
他のヒント
これは非常に古いですが、更新を監視する方法が必要な場合...シーケンスはグローバルに影響を受けるため、これを行うことで別のセッションでこの更新を監視するためのシーケンスを作成できます。
create sequence yourprogress;
UPDATE pagelinks SET pl_to = page_id
FROM page
WHERE
(pl_namespace, pl_title) = (page_namespace, page_title)
AND
page_is_redirect = 0 AND NEXTVAL('yourprogress')!=0;
その後、別のセッションでこれを行います(シーケンスはグローバルに影響を受けるため、トランザクションを心配しないでください):
select last_value from yourprogress;
影響を受けている行数が表示されるため、所要時間を見積もることができます。
最後にシーケンスを再起動して、もう一度試してください:
alter sequence yourprogress restart with 1;
または単にドロップ:
drop sequence yourprogress;
インデックスが必要です。または、ビルが指摘したように、すべてのテーブルで順次スキャンを実行する必要があります。
CREATE INDEX page_ns_title_idx on page(page_namespace, page_title);
CREATE INDEX pl_ns_title_idx on pagelink(pl_namespace, pl_title);
CREATE INDEX page_redir_idx on page(page_is_redirect);