ここではいくつかの要因が働いています:
- ネットワーク遅延とラウンドトリップ遅延
- PostgreSQLのステートメントごとのオーバーヘッド
- コンテキストスイッチとスケジューラの遅延
-
COMMIT
挿入ごとに1つのコミットを行う場合のコスト(あなたはそうではありません) コピーコード> -バルクローディングのための特定の最適化
ネットワーク遅延
サーバーがリモートの場合、ステートメントごとの固定時間「価格」、たとえば50ミリ秒(1/20秒)を「支払う」可能性があります。または、一部のクラウドホストDBの場合はさらに多くなります。次の挿入は最後の挿入が正常に完了するまで開始できないため、これは最大を意味します 挿入の速度は、1000/round-trip-latency-in-ms行/秒です。 50ms(「ping時間」)の遅延では、20行/秒になります。ローカルサーバー上でも、この遅延はゼロ以外です。 Wheras COPY
TCPの送信ウィンドウと受信ウィンドウを埋めるだけで、DBが行を書き込み、ネットワークが行を転送できるのと同じ速さで行をストリーミングします。遅延の影響をあまり受けず、同じネットワークリンクに毎秒数千行を挿入する可能性があります。
PostgreSQLのステートメントごとのコスト
PostgreSQLでステートメントを解析、計画、実行するためのコストもあります。ロックを取得し、リレーションファイルを開き、インデックスを検索する必要があります。 COPY
最初にこれらすべてを一度実行してから、できるだけ速く行をロードすることに集中しようとします。
タスク/コンテキスト切り替えのコスト
オペレーティングシステムが、アプリが行を準備して送信する間、postgresが行を待機することと、postgresが行を処理する間、postgresの応答を待機することを切り替える必要があるため、さらに時間コストがかかります。切り替えるたびに、少し時間が無駄になります。プロセスが待機状態に出入りするときに、さまざまな低レベルのカーネル状態を一時停止および再開するために、より多くの時間が無駄になる可能性があります。
COPYの最適化を見逃している
その上、 COPY
ある種の負荷に使用できるいくつかの最適化があります。たとえば、生成されたキーがなく、デフォルト値が定数である場合、それらを事前に計算してエグゼキュータを完全にバイパスし、PostgreSQLの通常の作業の一部を完全にスキップする下位レベルのテーブルにデータを高速ロードできます。 CREATE TABLE
の場合 またはTRUNCATE
同じトランザクションで、 COPY
、マルチクライアントデータベースで必要な通常のトランザクション簿記をバイパスすることで、読み込みを高速化するためのさらに多くのトリックを実行できます。
それにもかかわらず、PostgreSQLの COPY
物事をスピードアップするためにまだもっと多くのことをすることができます、それはまだ方法を知らないことです。テーブルの特定の割合を超えて変更する場合は、インデックスの更新を自動的にスキップしてから、インデックスを再構築できます。インデックスの更新をバッチで実行できます。もっとたくさん。
コミットコスト
最後に考慮すべきことは、コミットコストです。 psycopg2
なので、おそらく問題にはなりません。 デフォルトでは、トランザクションを開き、指示するまでコミットしません。自動コミットを使用するように指示しない限り。ただし、多くのDBドライバーでは、自動コミットがデフォルトです。このような場合、 INSERT
ごとに1つのコミットを実行します。 。これは、1回のディスクフラッシュを意味します。サーバーは、メモリ内のすべてのデータをディスクに確実に書き込み、ディスクに独自のキャッシュを永続ストレージに書き出すように指示します。これには長いかかる場合があります 時間、およびハードウェアに基づいて大きく異なります。私のSSDベースのNVMeBTRFSラップトップは、200 fsyncs /秒しか実行できませんが、非同期書き込み/秒は300,000回です。したがって、ロードされるのは200行/秒のみです。一部のサーバーは、50fsyncs/秒しか実行できません。 20,000を実行できるものもあります。したがって、定期的にコミットする必要がある場合は、バッチでロードしてコミットしたり、複数行の挿入を行ったりしてみてください。 COPY
最後にコミットするのは1つだけで、コミットコストはごくわずかです。ただし、これは COPY
も意味します データの途中でエラーから回復することはできません。バルクロード全体を元に戻します。