13

私は1000万行の大きなテーブルを持っています。そして、各行の統計値を取得する必要があります。たとえば、この値を生成する関数がありますGetStatistic(uuid)。この関数の動作は非常に遅く、結果の値はあまり変更されないためStatistic、テーブルに列を作成し、1日1回次のようなクエリを実行します。

UPDATE MyTable SET Statistic = GetStatistic(ID);

また、selectクエリでは、関数Statisticを呼び出さずに列を使用しますGetStatistic

問題は、本番サーバーには64個のCPUと大量のメモリがあるため、ほぼすべてのDBをRAMにキャッシュできますが、このクエリは1つのCPUしか使用せず、実行に2〜3時間かかります。

GetStatistic関数は、クエリのすべての実行中に一定であるテーブルを使用しUPDATEます。GetStatistic使用可能なすべてのCPUを使用して、異なる行を同時に並行して計算するようにpostgreを取得するようにクエリを変更できますか?

4

1 に答える 1

17

10より古いバージョンのPostgreSQLは、単一のバックエンドで各クエリを実行します。これは、単一のスレッドを持つプロセスです。クエリに複数のCPUを使用することはできません。また、単一のクエリ内で達成できるI / Oの同時実行性にも多少の制限があり、実際にはビットマップインデックススキャンの同時I / Oのみを実行し、それ以外の場合は同時I/OをOSとディスクシステムに依存します。

PostgreSQL10+は並列クエリをサポートしています。執筆時点(PostgreSQL 12リリース)では、並列クエリは読み取り専用クエリにのみ使用されます。並列クエリのサポートにより、一部のタイプのクエリでかなり多くの並列処理が可能になります。

Pgは、多数の小さなクエリの同時ロードに優れており、そのようにシステムを飽和させるのは簡単です。1つまたは2つの非常に大きなクエリに対してシステムリソースを最大限に活用するのは得意ではありませんが、より多くの種類のクエリに対して並列クエリのサポートが追加されるため、これは改善されます。


並列クエリのない古いPostgreSQLを使用している場合、またはクエリが並列クエリのサポートの恩恵を受けていない場合:

あなたができることは、仕事をチャンクに分割し、それらを労働者に配ることです。あなたはこれを次のようにほのめかしました:

クエリを変更してpostgreを取得し、使用可能なすべてのCPUを使用して、異なる行の並列でGetStatisticを同時に計算できますか?

DBlinkPL / ProxypgbouncerPgPool-IIなど、この種の作業を支援するように設計されたさまざまなツールがあります。または、自分で行うこともできます。たとえば、それぞれがデータベースに接続し、UPDATE ... WHERE id BETWEEN ? AND ?重複しないID範囲でステートメントを実行する8人のワーカーを開始します。より洗練されたオプションは、キューコントローラに約1000 IDの範囲をUPDATEその範囲のワーカーに渡してから、新しいIDを要求させることです。

64個のCPUは、64個の並行ワーカーが理想的であることを意味するわけではないことに注意してください。書き込みに関しては、ディスクI/Oも要因になります。UPDATEトランザクションを使用するように設定するcommit_delayと(このデータのビジネス要件に対して安全な場合)synchronous_commit = 'off'、同期による負荷を大幅に減らすことができれば、I/Oコストを少し抑えることができます。それでも、64人の同時ワーカーをはるかに下回る最高のスループットが達成される可能性があります。

GetStatisticおそらく現在のループの多い手続き型PL/pgSQL関数ではなく、インライン化可能なSQL関数またはビューに変換することで、関数を大幅に高速化できる可能性が高くなります。この機能を見せていただければ助かります。

于 2012-10-17T12:17:30.547 に答える