データベースにデータを初期投入するために、大量のテーブル挿入操作を行う必要がままあります。 本節では、この作業を効率よく行うためのちょっとした提言を示します。
自動コミットを無効にし、最後に一回だけコミットします。 (普通のSQLでは、これはBEGINを開始時に、COMMITを最後に発行することを意味します。 クライアント用ライブラリの中にはこれを背後で実行するものもあります。 その場合は、要望通りにライブラリが行っているかどうかを確認しなければなりません。) 各挿入操作で別個にコミットすることを許すと、PostgreSQLは行を追加するたびに多くの作業をしなければなりません。 1つのトランザクションで全ての挿入を行なうことによるもう1つの利点は、1つの行の挿入に失敗した場合、その時点までに挿入された全ての行がロールバックされることです。 その結果、一部のみがロードされたデータの対処に困ることはありません。
単一コマンドで全ての行をロードするために一連のINSERTコマンドではなく、COPYを使用してください。 COPYコマンドは行を大量にロードすることに最適化されています。 このコマンドはINSERTに比べ柔軟性に欠けてますが、大量のデータロードにおけるオーバーヘッドを非常に低減します。 COPYコマンドでテーブルにデータを投入する場合、コマンドはひとつなので、自動コミットを無効にする必要はありません。
COPYを使用できない場合、準備済みのINSERT文をPREPAREを使用して作成し、必要数回EXECUTEを実行する方がいいでしょう。 これにより、繰り返し行われるINSERTの解析と計画作成分のオーバーヘッドを省くことになります。
COPYを使用した大量の行のロードは、ほとんど全ての場合において、INSERTを使用するロードよりも高速です。 たとえ複数のINSERTコマンドを単一トランザクションにまとめたとしても、またその際にPREPAREを使用したとしても、これは当てはまります。
新規に作成したテーブルをロードする時、最速の方法は、テーブルを作成し、COPYを使用した一括ロードを行い、そのテーブルに必要なインデックスを作成することです。 既存のデータに対するインデックスを作成する方が、各行がロードされる度に段階的に更新するよりも高速です。
既存のテーブルに追加しているのであれば、インデックスを削除し、テーブルをロード、その後にインデックスを再作成することができます。 もちろん、他のユーザから見ると、インデックスが存在しない間データベースの性能は悪化します。 また、一意性インデックスを削除する前には熟考しなければなりません。 一意性制約によるエラー検査がその期間行われないからです。
大規模なデータをロードする時maintenance_work_mem設定変数を一時的に増やすことで性能を向上させることができます。 これは、B-treeインデックスをスクラッチから作成する時に既存のテーブルの内容はソートされている必要があるからです。 より多くのバッファページを使用するマージソートを許すことは、要求されるマージ経路が非常に少なくなることを意味します。 また、maintenance_work_memを増加させることで、外部キー制約の検証を高速に行うことができます。
大規模なデータをロードする時checkpoint_segments設定変数を一時的に増やすことで高速化することができます。 大量のデータをPostgreSQLにロードすることで、通常のチェックポイントの頻度(checkpoint_timeout設定変数により指定されます)よりも頻繁にチェックポイントが発生するためです。 チェックポイントが発生すると、全てのダーティページ(ディスクに未書き込みの変更済みメモリページ)はディスクに吐き出されなければなりません。 大量のデータロードの際に一時的にcheckpoint_segmentsを増加させることで、必要なチェックポイント数を減らすことができます。
テーブル内のデータ分布を大きく変更した時は毎回、ANALYZEを実行することを強く勧めます。 これは、テーブルに大量のデータをまとめてロードする場合も含まれます。 ANALYZE (または VACUUM ANALYZE)を実行することで、確実にプランナがテーブルに関する最新の統計情報を持つことができます。 統計情報が存在しない、または古い場合、プランナは、そのテーブルに対する問い合わせの性能を損なわせる、お粗末な問い合わせ計画を選択する可能性があります。