PostgreSQLクエリがどれくらい進んでいるかを調べるにはどうすればよいですか?


35

SELECT ... INTOクエリが実際に処理する行の数については、かなりまともな考えがあります(たとえば、何行が具体化されるかがわかります)。

Postgresは完全なパーセンテージを教えてくれないことを理解していますが、宛先テーブルにポンプで送られた行またはSELECTクエリによって読み取られた行数を見つけることができる方法(ログ、システムテーブルなどに深く埋め込まれている)があります?

回答:


33

ダニエルベリテが述べたように、一般的な解決策はないようです。ファイルからテーブルにデータをロードする場合、次の手法を使用してロードの進行状況を取得できます。

COPYコマンドコンソールの進行状況バー

空のテーブルを作成します。

CREATE TABLE mytest (n int);

テーブルに読み込むための1,000万行のデータファイルを作成します。

$ seq 10000000 > /tmp/data.txt

ファイルからテーブルにデータを読み込み、進行状況バーを表示します。

$ pv /tmp/data.txt | psql -c "COPY mytest FROM STDIN;"

デモ

ここに画像の説明を入力してください

仕組み

コピーコマンドのSTDINオプションを使用すると、別のプロセスからコピー操作のデータを入力できます。pvコマンドはファイルを出力し、その進行状況を追跡して、進行状況バー、ETA、合計経過時間、データ転送速度を表示します。

COPYコマンドのグラフィカルな進行状況バー

同じ一般的な手法を使用して、グラフィカルアプリケーションまたはWebベースのアプリケーションでプログレスバーを表示できます。たとえばpythonを使用して、psycopg2モジュールでは、選択したファイルオブジェクトでcopyコマンドを呼び出すことができます。その後、ファイルオブジェクトの読み取り量を追跡し、進行状況バーを表示できます。


2
pv以前にこのコマンドに出くわすことはなかったし、デフォルトではDebianサーバーにインストールされていませんでしたが、リポジトリにあります。説明には、「pv(Pipe Viewer)を2つのプロセス間の通常のパイプラインに挿入して、データの通過速度を視覚的に示すことができる」とあります。非常に便利なコマンド!
リチャードターナー

27

サポートされている一般的なメソッドはないようですが、個々のクエリの進行状況を評価するために、限られたコンテキストで使用できるいくつかのトリックがあります。ここにそれらのいくつかがあります。

シーケンス

SELECTまたはUPDATEクエリにanyが含まれる場合nextval(sequence_name)、またはINSERTにnextvalデフォルトとしてが含まれる宛先列がある場合、現在のシーケンス値はを使用して別のセッションで繰り返しクエリできますSELECT sequence_name.last_value。シーケンスがトランザクションによって制限されていないため機能します。実行プランが、クエリ中にシーケンスが線形に増加するようなものである場合、進行インジケータとして使用できます。

pgstattuple

pgstattupleののcontribモジュールは、データページに直接覗き見できる機能を提供します。タプルが空のテーブルに挿入され、まだコミットされていない場合、それらは関数のdead_tuple_countフィールドでカウントされるpgstattupleようです。

9.1のデモ:空のテーブルを作成する

CREATE TABLE tt AS (n numeric);

10M行を挿入しましょう:

INSERT INTO tt SELECT * FROM random() from generate_series(1,10000000);

別のセッションでは、挿入中に毎秒pgstattupleを確認します。

$ while true;
   do psql -Atc "select dead_tuple_count from pgstattuple('tt')";
   sleep 1;
  done

結果:

0
69005
520035
1013430
1492210
1990415
2224625
2772040
3314460
3928660
4317345
4743770
5379430
6080950
6522915
7190395
7953705
8747725
9242045
0

挿入が完了すると、0に戻ります(すべてのタプルが表示され、有効になります)。

このトリックは、テーブルが新しく作成されていない場合にも使用できますが、初期dead_tuple_count値にはゼロ以外の値が含まれている可能性が高く、autovacuumなどの他の書き込みアクティビティが実行されている場合も同時に変更される可能性があります(おそらく? autovacuumで予想される並行性)。

ただし、テーブル自体がステートメント(CREATE TABLE ... AS SELECTまたはSELECT * INTO newtable)によって作成されている場合は、作成がトランザクション化されるため、使用できません。回避策は、行のないテーブルを作成し(add LIMIT 0)、次のトランザクションでデータを追加することです。

pgstattuple無料ではないことに注意してください:呼び出しごとにテーブル全体をスキャンします。また、スーパーユーザーに制限されています。

カスタムカウンター

Pavel Stehuleのブログでは、 指定された実行回数で通知を発生させるCで実装されたカウンター関数を提供しています。executorが関数を呼び出すには、何らかの方法で関数をクエリと組み合わせる必要があります。通知はクエリ中に送信され、別個のセッションを必要とせず、それらを表示するSQLクライアントのみが必要です(psql明らかな候補です)。

INSERT INTOの例は、通知を上げるために作り直されました。

/* transformation */
INSERT INTO destination_table
   SELECT (r).*
  FROM (SELECT counter(to_destination_table(_source), 1000, true) r
           FROM source _source) x

関数に関するstackoverflowの関連質問:
実行時間の長いPostgreSQL関数からクライアントへの進捗状況を報告する方法

将来のオプション?

2017年5月の時点で、開発者コミュニティに提出された有望なパッチがあります。 [PATCH v2]実行時間の長いSQLクエリの進行を監視するProgressコマンド

PostgreSQL 11以降では一般的なソリューションになる可能性があります。進行中の機能に参加したいと考えているユーザーは、最新バージョンのパッチを適用し、提案されたPROGRESSコマンドを試してください。


3

@AmirAliAkbariが彼の答えで述べたように、進行状況レポート機能が拡張されなくなるまで、OSレベルの回避策があります。

これはLinuxでのみ機能しますが、おそらくすべてのオペレーティングシステムで簡単にグーグル化できる同様のソリューションがあります。

そのバックエンドのすべてを使用して、シンプルなシングルスレッドのプロセスであることを最大の利点ともPostgreSQLのの欠点、lseek()read()write()彼らは共有MEMとロックに相互作用している間に、そのテーブルのファイルを操作します。

この結果、すべてのバックエンドプロセスは常に単一のクエリで動作し、簡単に見つけることができ、簡単にstraced。

まず、以下からバックエンドPIDを確認できますSELECT * FROM pg_stat_activity;

29805270 | dbname  | 20019 |    16384 | username  |                  |             |                 |          -1 | 2018-09-19 21:31:57.68234+02  | 2018-09-19 21:31:59.435376+02 | 2018-09-\
20 00:34:30.892382+02 | 2018-09-20 00:34:30.892386+02 | Client          | ClientRead | active              |       92778 |        92778 |  INSERT INTO ...something...

3列目はpidです。PostgreSQLでは、バックエンドのLinuxプロセスpidと同じです。

次に、たとえばstrace -p 20019 -s 8192:で追跡できます(-s 8192postgresqlは8192バイトの長いブロックで動作するため便利です)。

sendto(10, "C\0\0\0\17INSERT 0 1\0Z\0\0\0\5T", 22, 0, NULL, 0) = 22
recvfrom(10, "Q\0\0\1\267 INSERT <removed by @peterh>", 8192, 0, NULL, NULL) = 440
sendto(10, "C\0\0\0\17INSERT 0 1\0Z\0\0\0\5T", 22, 0, NULL, 0) = 22
lseek(298, 343634345)...
read(298, "<block data which was read in>"....
write(298, "<block data which was written out>"...

意味:

  • sendtoバックエンドがクライアントに何かに答えると発生します。この例では、INSERTクエリの結果に応答します。
  • recvfromバックエンドがクライアントから何かを取得した場合に発生します。この例では、通常は新しいクエリであり、さらに別のクエリINSERTです。
  • lseek バックエンドがテーブルファイル内で位置を切り替えると発生します。
  • read バックエンドがテーブルファイルからブロックを読み込むと発生します。
  • write バックエンドがブロックをテーブルファイルに書き込むと発生します。

readおよびの場合write、表でそのブロックの内容を確認することもできます。それは何をしていて何をしているのかを理解するのに大いに役立ちます。

の場合recvfrom、バックエンドが取得した実際のクエリを確認できます。


2

他の回答で述べたように、現在、一般的に進捗状況を報告する直接的な方法はありません。

PostgreSQLには、コマンド実行中に特定のコマンドの進行状況を報告する機能があります。現在、進捗レポートをサポートする唯一のコマンドはVACUUMです。これは将来拡張される可能性があります。

ただし、9.6以降、VACUUM実行中の場合は常に、pg_stat_progress_vacuumビューには、現在バキューム処理している各バックエンド(自動バキュームワーカープロセスを含む)ごとに1つの行が含まれます。詳細についてpg_stat_progress_vacuumは、ドキュメント:27.4 Progress Reportingをご覧ください。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.