web-dev-qa-db-ja.com

(トランザクションが終了する前に)トランザクションが変更した行数を判別する方法はありますか?

次のクエリを実行する約3億2000万行のテーブルがあります。

UPDATE my_table SET state = TRIM(state)

言うまでもなく、これは90時間以上実行され(木曜日の午後以降)、まだ終了していません。

多かれ少なかれ、今までに変更された行数を知りたいのですが。実行中のトランザクションからこの情報を取得する方法はありますか?

検索しようとすると、pgstattuple関数を使用してテーブルに追加されているnew行の概算を決定する方法がわかりました。

select dead_Tuple_count from pgstattuple('my_table');

しかし、これは変更された行数に関する興味深い情報を示していないようです。

5
Giacomo Alzetta

少々強引ですが、コミットされていないUPDATEの進行状況を確認する方法は少なくとも1つあります。

Postgresは 行のバージョン管理 によってトランザクションの分離を処理します。それらの implementation では、すべてのレコードバージョンに、それを表示できる最小および最大のトランザクションID(それぞれxminおよびxmax)でタグ付けします。

このスキームでは、UPDATEは、ターゲットレコードのxmaxを現在のトランザクションID(DELETEと同等)に設定し、トランザクションIDで更新されたコピーを作成することで機能します。 xminINSERTと同等)。

これらの システム列 は照会できるため、UPDATEpg_stat_activity.backend_xid から取得できる)のトランザクションIDを指定すると、次のようになります。処理された行数を出力します。例:

SELECT COUNT(*)
FROM my_table
WHERE xmax = 2357

トランザクションが savepoints を設定している場合、状況は少し乱雑になります。その場合、xmaxpg_stat_activity(またはどこにも表示されないサブトランザクションIDになります)それ以外、私が知る限り)。その場合、進行中のトランザクションまたはロールバックされたトランザクションのいずれかによって、更新/削除のマークが付けられているすべての行を次のように検査できます。

SELECT xmax, COUNT(*)
FROM my_table
WHERE xmax <> 0
GROUP BY xmax

...そしてそこから、興味のあるIDを特定するのはそれほど難しくありません。

2
Nick Barnes

@Nick Barnesの提案に従ってpg_table_sizeを使用することで、進行状況の概算を得ることができました。ただし、これが機能するのは、1つのトランザクションのみがテーブルを変更している場合のみです。テーブルを変更する複数のトランザクションがある場合、特定のトランザクションがどれだけ完了したかを知ることはできません。

さらに、進行状況の見積もりを取得できるようにするには、クエリによって影響を受ける行数を知っておく必要があります。

したがって、次のコマンドを使用します。

SELECT pg_table_size('my_table');

テーブルのサイズを取得できます(これには、コミットされたデータとコミットされていないデータの両方が含まれます)。

テーブルの初期サイズinitial_size、初期行数N、およびクエリの影響を受ける行数Kがわかっている場合は、データの推定値を取得できますあなたのクエリが書くこと:

delta_size = (initial_size/N)*K

現在のテーブルサイズがcurrent_sizeの場合、進行状況の推定は次のようになります。

progress_perc = 100*(current_size - initial_size)/delta_size

テーブルの初期サイズがわからない場合は、テーブルの増加を確認することで見積もることができます。

pg_table_sizeを使用して、特定の時間間隔でテーブルがどれだけ大きくなるかを確認しますdelta_t、たとえば1時間。次に、方程式から初期サイズを推定できます。

initial_size = current_size - growth*num_delta_t_passed

クエリを使用してトランザクションが開始されてからの時間を取得できます。

SELECT pid, age(clock_timestamp(), query_start), usename, query 
FROM pg_stat_activity 
WHERE query != '<IDLE>' AND query NOT ILIKE '%pg_stat_activity%' 
ORDER BY query_start desc;

this Gist page から取得)

Postgresql 9.6の場合、正確な応答を得ることができないようです。 Postgresql 10以降にもっと良いオプションがあるかどうかはわかりません。

3
Giacomo Alzetta

MVCCのpostgres実装では、他のトランザクションによって現在更新されている行数を正確に通知するxmaxメタフィールドをクエリできます(同じテーブルで書き込み操作を実行している他のトランザクションがない場合)時間)。

だから次のようなもの:

select count(1) from my_table where xmax <> 0;

更新された行数が表示されます。

3
Arkhena