パフォーマンスチューニング9つの技 ~「書き」について~
PostgreSQLインサイド

今回は、実際の業務において押さえておきたいパフォーマンスチューニング手法の「書き」について解説します。ここでの「書き」とは、テーブルデータの更新だけでなく、同時に行われるインデックスの更新やトランザクションログ書き出し、チェックポイント処理などのデータ更新処理が対象であり、この際に発生する無駄なディスクI/Oを可能な限り削減することがテーマです。これは、パフォーマンスチューニングにおいて一番重要な点になります。以下に、「パフォーマンスチューニング9つの技」の全体概要を示します。

パフォーマンスチューニング9つの技 内容
書き 書込み保証を見極める
  • 各種バッファーのサイズや、チェックポイント処理などのディスク書き込みタイミングを調整する
インデックスの更新を抑止する
  • 大量データ挿入時は一時的にインデックスを外す
  • 更新頻度が高い場合はFILLFACTORやHOTを利用する
大量データは一括 / 並列で格納する
  • COPYコマンドの利用や多重実行でデータを格納する
探し インデックスを有効活用する
  • ソート処理をインデックススキャンで代用する
  • 検索方式Index Only Scanを活用する
  • 複合インデックスは絞り込める順に記述する
  • OR条件を工夫する
  • 式インデックスを利用する
実行計画を評価し制御する
  • 実行計画を見る
  • 実行計画を制御する
  • 統計情報を固定化する
クライアント側で無駄を削減する
  • プリペアド文、コネクションプーリング、ユーザー定義関数を利用する
  • フェッチサイズを調整する
基盤 データを整理し、統計情報を最新化する
  • VACUUMで不要領域を再利用可能にする
  • REINDEXで不要領域を削除する
  • ANALYZEで統計情報を最新化する
  • VACUUM FREEZEでトランザクションIDを凍結状態にする
パラメーター調整で高速化する
  • 作業メモリーサイズ、遺伝的問合せ最適化、プランナー推定コスト、並列処理、コンフリクト軽減のためのパラメーターを調整する
資源分割とロック回避で高速化する
  • テーブルスペースやパーティショニングを活用する
  • ロック競合を軽減する

今回の記事は、パフォーマンスチューニングの観点と仕組みを理解することに主眼を置いています。具体的な対処方法についてはシステムによって異なるため、マニュアルの確認や、各種チューニングサービスのご利用をご検討ください。なお、この記事で対象にしているPostgreSQLのバージョンは9.5以降です。

本記事の構成

本記事「パフォーマンスチューニング9つの技」は以下4つの記事から構成されています。他の記事も併せてご覧ください。

1. パフォーマンスチューニングの「書き」とは

一般的にデータベースは、大量データを扱い、大量の問い合わせや更新を高速に処理し、さらに障害発生時にはCOMMITされたデータを保証するための仕組みを持っています。そのため、データの参照や更新は極力メモリー上で行い、ディスクへのアクセスは最小限のコストで行えるよう効率化されています。しかし、データベースに対するシステム要件は様々であり、その要件に合わせて、適切なサイズのメモリーを割り当てたり、ディスクへの書き出しタイミングを調整したりすることで、ディスクI/Oの回数や量を減らし、パフォーマンス向上につなげていく事ができます。
ただし、ディスクI/Oを減らす施策だけを行うと、障害発生時の復旧時間が長くなったり、最新の状態に復旧できなくなったりするデメリットがあります。そのため、システム要件に見合った最適なバランスを考えることが大切です。
これらを考慮して最もボトルネックになりやすいディスクI/Oを削減することが「書き」のポイントであり、それを実現するためには、PostgreSQLの書き込み保証のメカニズムの理解が必要です。以下に、その書き込み保証メカニズムの概要図を示し、その動作について説明します。

PostgreSQLの書き込み保証メカニズム

図1 PostgreSQLの書き込み保証メカニズム

各プロセス、メモリー、ファイルの説明は、「PostgreSQLのアーキテクチャー概要」を参照してください。

1.1 書き込み保証のメカニズムについて

PostgreSQLには、COMMITした更新データを確実にディスクに書き込むための、データ保証のメカニズムがあります。例外などはありますが、その基本的な流れを押さえておく必要があります。以下に、更新系SQLが実行された場合、および、リカバリーが実行された場合の、一連の動作の流れについて説明します。

更新系SQLが実行された場合の動作

  • (1)更新系のSQLが実行されると共有バッファー上でテーブルやインデックスの更新を実施します。必要な情報が共有バッファー上にない場合、ディスクから共有バッファー上にデータを読み込んでキャッシュします。
  • (2)更新内容をトランザクションログとしてWALバッファーに書き出します。

書き込み保証(更新SQL実行時のデータとWALの書き出し処理)

図2 書き込み保証(更新SQL実行時のデータとWALの書き出し処理)

  • (3)(1)(2)を繰り返した後にCOMMITが実行されると、WALバッファーにCOMMITしたことを書き出し、それまでのWALバッファーの情報をWALファイルに書き出します。

書き込み保証(COMMIT時のWALの書き出し処理)

図3 書き込み保証(COMMIT時のWALの書き出し処理)

  • (4)定期的なチェックポイント処理により、共有バッファーの更新されたデータページ(ダーティページ)をデータファイルに書き出します。なお、チェックポイント処理が終了したことで不要になったWALファイルは削除します。

書き込み保証(チェックポイント時のテーブルデータの書き出し処理)

図4 書き込み保証(チェックポイント時のテーブルデータの書き出し処理)

リカバリーが実行された場合の動作

障害の発生などによりPostgreSQLが停止した後、再度PostgreSQLを起動してリカバリーが実施される際には、チェックポイントの位置からWALを適用していくことになります。
例として、障害が発生してPostgreSQLが停止した、リカバリー前の状態を図5-1に示します。更新処理AからDが順に実行され、更新処理Dの実行中に障害が発生してPostgreSQLが停止したものとします。また、更新処理Aが完了後、更新処理Bの途中でチェックポイント処理が実行されたものとします。

書き込み保証(リカバリー前の状態)

図5-1 書き込み保証(リカバリー前の状態)

次に、リカバリーを実行する際の動作について図5-2に示します。PostgreSQLのリカバリー処理は、チェックポイントより後の更新処理は、COMMITされた変更履歴(②③のWAL)がWALファイルに残っているため、この変更履歴を適用していくことで、リカバリーを実施します。その結果、障害が発生する前の、更新処理Cの状態まで復元されることになります。

書き込み保証(リカバリー時の動作)

図5-2 書き込み保証(リカバリー時の動作)

2. パフォーマンスチューニングの「書き」の技

ここからは、実際にデータベースが使用するメモリーの使い方を調整したり、ディスクへの読み書きのタイミングを調整したりして、ディスクI/Oを減らすための考え方と対処方法について説明します。また、大量データの挿入時にも大量のディスクI/Oが発生するため、その際の対処方法についても説明します。

2.1 書込み保証を見極める

ディスクI/Oの発生を減らすためには、各種バッファーのサイズやアクセスタイミングの調整が重要となります。ここでは、各種バッファーのサイズやアクセスタイミングを適切な値に設定するための考え方について、以下の内容で説明します。なお、括弧の中のキーワードは、設定ファイルpostgresql.confの設定パラメーター名です。

共有バッファー(shared_buffers)の見積もりの考え方

共有バッファーのサイズのデフォルト値は128メガバイトなので、パフォーマンスを引き出すためには、大きな値に設定する必要があります。PostgreSQLのマニュアルでは、1ギガバイト以上のRAMを載せた専用データベースサーバーを使用している場合、システムメモリーの25%程度割り当てるのが妥当とあります。あまり値を大きくし過ぎると、OSのシステムキャッシュに利用するメモリーが少なくなります。すると、共有バッファーのページをディスクに書き込んだり読み込んだりする際に、OSのシステムキャッシュが無い状態でディスクにアクセスすることになるため、ディスクI/Oが多く発生し時間がかかることになります。そのため、実際にデータベースを動作させてパフォーマンスを測定しながら調整していく必要があり、必要以上に大きな値を設定することは推奨しません。実際には、システムメモリーの25%から30%程度が一般的です。

参考

PostgreSQLのコネクション数、アクセスするテーブル、および、利用するカーソルが多い場合に、共用バッファーの確保ができないと、以下のエラーが起きることがあります。

ERROR: no unpinned buffers available

このエラーは、共有バッファー上のすべてのページが利用中で、新たに共有バッファーにデータを読み込めなかったことを示します(バッファーに対してロックを取ることをpinと呼びます)。最低でも以下の計算式で計算されるサイズ以上が必要になります。

max_connections × 1SQLでアクセスするテーブル数 × (カーソル数 + 1) × 8(キロバイト)

共有バッファーに対してpinのロックを取る処理は、その他にも、並列検索処理、autovacuum処理、バックエンドライタプロセス内の処理などがあります。また、共有バッファーには、インデックス、空き領域マップ、可視性マップも格納されるため、ある程度余裕を持たせたサイズを設定しておく必要があります。

トランザクションログバッファー(WALバッファー:wal_buffers)の見積もりの考え方

1章の書き込み保証のメカニズムで説明したように、WALバッファーの内容は基本的にCOMMIT時にWALファイルに書き込みます。そのため、1つのトランザクションで大量の更新を実施すると、WALファイルに書き込む前にWALバッファーの領域があふれることがあります。WALバッファーの領域があふれると、一度WALバッファーの内容をWALファイルに書き出して空きを作り、残りのデータをWALバッファーに書き込めるようにします。その結果、ディスクへの書き込み回数が増え、ディスクI/Oが増加することになります。
WALファイルへの書き込みはディスクの連続した場所に書き込むので、一度にまとめて書き込んだ方が速くなります。そのため、WALバッファーのサイズを大きくして領域があふれることがないようにしておくことで、ディスクへの書き込み回数を減らし、パフォーマンスの向上が図れます。なお、この領域のあふれを直接確認する手段は無いため、実際の業務で想定されるピーク時に発生するディスクI/Oの量(Linuxの場合はiostatコマンドなど)を確認しながら、WALバッファーのサイズを調整していく必要があります。

参考

FUJITSU Software Enterprise Postgres」では、独自システムビュー「pgx_stat_walwriter」の「dirty_writes」のカラム情報を参照することで、WALバッファーがあふれてディスクに書き込みが発生した回数(累積)を確認することができます。そのため、この値を見ながらバッファーのサイズを調整していくことが可能です。

注意事項

COMMIT発行の契機でWALバッファーの内容をWALファイルへ書き出しますが、その際、WALバッファーの先頭からCOMMITまでの内容をすべて書き出します。その中には、他のトランザクションが処理したWALも含まれる可能性があります。例えば、図6の例においてCOMMIT1のタイミングでは、更新SQL1から更新SQL4、および、COMMIT1の内容のすべてがWALファイルへ書き込まれます。WALバッファーのサイズを見積もる際には、同時に実行する他のトランザクションのWALサイズも考慮し、WALバッファーがあふれてディスクへの書き込み回数を増やさないよう注意する必要があります。

複数トランザクション実行時のWALの書き出し例

図6 複数トランザクション実行時のWALの書き出し例

WALの遅延書き込み(commit_delay)の見積もりの考え方

短いトランザクションが高多重で実行されると、それらのCOMMIT時には何度もWALファイルへの書き込みが発生することで、ディスクI/Oのボトルネックになることがあります。それを防ぐために、WALファイルへの書き込みを遅らせるcommit_delayパラメーターがあります。なお、このパラメーターが有効に動作するのは、確実に物理ディスクに書き込まれるようにするためのfsyncパラメーターが有効で、かつ、commit_siblingsパラメーターで指定された数以上の実行中トランザクションが存在する状態のときです。最初のCOMMITを実行したトランザクションが、commit_delayパラメーターで指定された時間だけWALファイルへの書き込みを待ち、その間にCOMMITされたものすべてをまとめてWALファイルへ書き込むように制御されます(デフォルトでは0となっており、他のトランザクションを待つことはありません)。
図7は、COMMIT1を実行してから、commit_delayパラメーターで指定された時間が経過する間にCOMMIT2とCOMMIT3が実行された例です。この場合、COMMIT1は、COMMIT2とCOMMIT3の分もまとめてWALファイルへ書き込みます。その結果、ディスクへの書き込み回数を3回から1回にまとめることができます。デメリットとしては、COMMITの実行時間が、最大でcommit_delayパラメーターで指定した時間分だけ長くなります。なお、遅延書き込み時間の値の決定には、実際の業務で想定される複数トランザクション実行時において発生するディスクI/Oの量(Linuxの場合はiostatコマンドなど)が減ることを確認しながら調整していく必要があります。ただし、アプリケーション全体としてのレスポンスに影響がないことも併せて確認してください。

複数トランザクション実行時のWALの書き出し例(WALの遅延書き込み)

図7 複数トランザクション実行時のWALの書き出し例(WALの遅延書き込み)

チェックポイント処理の見積もりの考え方(checkpoint_timeout、max_wal_size、checkpoint_completion_target)

チェックポイント処理は、checkpoint_timeoutパラメーターで設定された時間(チェックポイント間隔)が経過するか、あるいは、WALの量がmax_wal_sizeパラメーターで設定された量に達するか、どちらかの条件が満たされると実行されます。実行されると、共有バッファー上の変更があったダーティページの内容をディスクへ書き込みます。そのため、これらのパラメーターを適切に設定しておかないと、ディスクI/Oが多く発生し、パフォーマンスに影響があります。
チェックポイント時の書き込みは、すべての変更ページを一度に書き込むよう処理すると、大量の書き込みが必要になってしまうことがあるため、一定の期間に分散して実行することでデータベース全体のパフォーマンス劣化を極力抑えるよう働きます。どの程度分散させるかは、図8に示すように、checkpoint_completion_targetパラメーターで、チェックポイント間隔の割合として指定します。例えば、デフォルト値0.5の場合、チェックポイント間隔の半分の時間でチェックポイント処理が終わるように実行され、ディスクへ書き込みが行われます(なお、PostgreSQL 14にて、デフォルト値は0.9に変更されました)。

チェックポイント処理について

図8 チェックポイント処理について

checkpoint_timeoutパラメーターの値については、デフォルト値は5分と小さいため、30分程度に設定することを推奨します。なお、データ更新が少ない運用の場合には、値を大きくする方が、チェックポイント処理の頻度を下げられるため有利です。max_wal_sizeパラメーターの値については、実際の運用で出力されるWALの量を測定して決める必要があります。見積もり方としては、1回のチェックポイント間隔(checkpoint_timeoutパラメーターで指定した時間)で発生するWALの量だけでなく、チェックポイント処理中(checkpoint_timeout × checkpoint_completion_targetの時間)に新たに発生するWALの量も加算するよう、考慮してください。また、実際の運用時と同じ状況で試行し、ログメッセージに「LOG: checkpoints are occurring too frequently ・・・」が出力された場合には、設定値を大きくするよう調整してください。

参考

大量データの格納時には十分にWALの格納量を増やし、チェックポイント間隔も長くする

大量データを格納する場合、max_wal_sizeパラメーターの値が小さいと、チェックポイント処理が多く発生して時間がかかるため、max_wal_sizeパラメーターを十分に大きくする必要があります。また、チェックポイント間隔の時間が短い場合も、チェックポイント処理がその時間内に終わらないため、常にディスクI/Oが出続けます。さらに、最後のチェックポイントの位置が更新できないためWALを削除できない状況となり、WALファイルの量が増加するなどの問題が発生します。そのため、チェックポイント間隔についても必要に応じて長くし、時間内にチェックポイント処理が完了するようにすべきです。
ここでも、大量データを格納した際のデータ量を見積もるか、あるいは、ログメッセージ「LOG: checkpoints are occurring too frequently ・・・」の有無を確認しながらパラメーターの値を調整します。

実際のWAL量を測定する方法(一例)

データベースを実際の運用時と同じ状況で試行しながら、pg_current_xlog_insert_location()関数(注1)を一定時間毎に実行し、それぞれの時点の「WALログの挿入位置」を取得します。その後、pg_xlog_location_diff()関数(注2)を使って2点間の「WALログの挿入位置」の差分をバイト数で算出することで、時間当たりのWAL量(バイト)を調べることができます。

  • 注1
    PostgreSQL 10より、関数名がpg_current_wal_insert_lsn()に変わりました。
  • 注2
    PostgreSQL 10より、関数名がpg_wal_lsn_diff()に変わりました。

チェックポイント処理後のディスクページ全体書き込みの考慮(full_page_writes、wal_log_hints)

チェックポイント処理により共有バッファー上のページをディスクに書き込む際、OSのクラッシュなどで全てのページが書き出せなかった場合、データベースのリカバリー時にクラッシュする可能性があります。PostgreSQLはその対策として、チェックポイント処理後、各ページに対する最初の更新の時に、ページ全体をWALに書き込んでおくことで、リカバリー時に正しく復旧されることを保証する機構があります。この機構は、full_page_writesパラメーターやwal_log_hintsパラメーターがonの場合に動作します(デフォルトでfull_page_writesはon、wal_log_hintsはoffです)。

チェックポイント処理後のディスクページ書き込み

図9 チェックポイント処理後のディスクページ書き込み

そのため、チェックポイント直後は、通常よりも多くのWALが出力されるようになり、パフォーマンスに影響が出ます。特にwal_log_hintsパラメーターをonにした場合は、SELECT文の実行などでヒントビット(注3)が更新されただけでもページ全体の書き込みが発生するため、注意が必要です。具体的なパフォーマンス影響の現象としては、一度に大量のディスクI/Oが発生することによるデータベースの一時的なレスポンス低下や、ストリーミングレプリケーション構成時において一度に大量のWALが出ることでWALの書き出しが発生し、本来ストリーミングレプリケーションに必要なWALが消えることにつながります。その対策としては、チェックポイント間隔を大きくすることや、必要なWALを保持されやすくするためにwal_keep_segmentsパラメーター(PostgreSQL 13よりwal_keep_sizeに変更)の値を大きくすることを検討してください。

  • 注3
    ヒントビットとは、COMMITまたはABORTされたトランザクションにより作成、削除されたレコード(タプル)に印を付けるために使用されるものです。
参考

checkpoint_timeout、max_wal_sizeパラメーターを大きくすることのメリットとデメリット

これらのパラメーターの値を大きくすることで、チェックポイント処理の頻度を下げることができます。そのため、full_page_writes、wal_log_hintsで説明したチェックポイント処理後の最初の更新でページ全体を書く処理を減らすことができ、ページをディスクへ書く処理もチェックポイントの間隔が延びることで分散させて実行することができるため、全体的にディスクI/Oの量を減らすことができます。
ただし、値を大きくすることで保持するWALの量が増え、ディスクサイズを圧迫します。また、障害発生時の復旧は、WAL適用により復旧しますが、適用しなければいけいないWALが増えるため、復旧までの時間が増加します。そのため、障害発生時の復旧時間を気にする場合は、大きな値を指定すると復旧に時間がかかるため問題となります。

2.2 インデックスの更新を抑止する

ここでは、大量データを扱う場合、および、更新が頻繁に発生するテーブルを利用する場合のインデックスの扱いについて、以下の内容で説明します。

大量データ挿入時はインデックスを付けない

インデックスが定義されているテーブルへのINSERT文やCOPYコマンドによる大量データ挿入時には、その都度インデックスデータを変更していきます。これは、データをすべて挿入後にインデックスを作成する場合よりも時間がかかります。そのため、初期創成時に大量データを挿入する場合は、インデックスなしの状態でデータを格納し、格納後にインデックスを作成する方が高速に処理されます。

具体的な手順例を以下に示します。

  1. CREATE TABLE文で、テーブル定義する(CHECK制約は付けておく)
  2. COPY FROMコマンドにより、大量データを挿入する
  3. CREATE INDEX文で、インデックスを作成する
  4. ALTER TABLE文で、インデックスを使用する制約や外部キー制約を追加する

なお、大量データ挿入後にインデックスを作成する場合、maintenance_work_memパラメーターの値を大きくすることでCREATE INDEXの際に利用できるメモリーの量が多くなり、さらに処理速度の向上が見込めます。

更新が頻繁に発生するテーブルは、FILLFACTORでインデックス更新を不要にする

インデックスが利用されているテーブルを更新する場合、テーブルデータの更新と共に、関連するインデックスについても更新が必要になります。そのため、更新が頻繁に発生するテーブルについては、インデックスがパフォーマンスのボトルネックになる場合があります。ここでは、テーブル更新のボトルネックを抑えるためのFILLFACTORという機構を利用することで、結果的にインデックス更新を不要にできる仕組みと利用方法について、順を追って説明します。

PostgreSQLの追記型アーキテクチャーの仕組みにより、UPDATE処理を行う際、更新前レコードに削除された情報を追記し、そのレコードを残したまま、更新後レコードを追記していきます。その際、共有バッファー上の同じページに更新後レコードが格納できた場合は、更新対象がその1ページ内で済むため、UPDATE処理のコストが低くなります(図10のa.)。一方、更新後レコードを別のページに追記する場合には、データファイルからの新たなページの読み出しが発生する可能性があるため、UPDATE処理のコストは高くなります(図10のb.)。

更新後レコードの追記ページについて

図10 更新後レコードの追記ページについて

PostgreSQLには、UPDATE時に同じページに更新レコードを格納しやすくするための、FILLFACTORと呼ばれる仕組みがあります。FILLFACTORは、INSERT時に指定された割合までしかデータを格納させないようにします。この割合の値は、CREATE TABLEやALTER TABLE文のパラメーターで指定できます。例えば、FILLFACTORにページ全体を100(%)として、80という値を指定しておくと、INSERT時にはページ内に20%の空きスペースを作るよう動作します。すると、UPDATE時には、空きスペース部分に更新後レコードを格納していけるので、同じページに更新後レコードが格納しやすくなります。なお、デフォルトでは、FILLFACTORの値は100になっているので空きスペースを作りません。FILLFACTORを設定するデメリットとしては、空きを必ず作るため、実際よりも多くのディスク容量を使ってしまうことが挙げられます。

FILLFACTORによる空きスペースの利用について

図11 FILLFACTORによる空きスペースの利用について

さらに、同じページ内で更新ができた場合には、HOT(Heap Only Tuple)と呼ばれる機構が働きます。通常、UPDATEを行うと、更新後レコードをテーブルとインデックスの両方に追加します。そのため、UPDATE時には、インデックスとテーブルの2つのデータを更新するため、処理のコストが高くなります。

別ページに更新後レコードを追加したときのインデックス更新について

図12 別ページに更新後レコードを追加したときのインデックス更新について

HOTによる更新は、UPDATE後のデータがUPDATE前のデータと同じページ内に格納でき、かつ、インデックスのカラムの値に変更がない場合に限り、インデックスは更新せず、更新前レコードに更新後レコードの位置を保存することで、処理コストの上昇を抑えることができます。

HOTによる更新について

図13 HOTによる更新について

更新が頻繁に発生するインデックスは、FILLFACTORでページ分割を抑える

インデックスについても、追加するデータが該当ページに入り切らなくなると、そのページは分割されて増加していきます。CREATE INDEXやALTER INDEXのFILLFACTORパラメーターの値を調整し、効果的に空きスペースを作ることで、ページの分割が起こりくくなり、高速化が見込めます。

B-treeインデックスの例

B-treeインデックスでは、初期インデックス構築時や一番右端のリーフページを拡張する際に、この割合を使用してページを分割します。図14のように、右側2番目のリーフページを分割する際は、FILLFACTORの割合を残して、拡張していきます。デフォルトは90であり、90%のデータを残して10%を新しいリーフページに移動させます。

B-treeインデックスの分割例(FILLFACTOR指定時)

図14 B-treeインデックスの分割例(FILLFACTOR指定時)

CREATE INDEXによりインデックスを作成するときは、ソートされたレコードからデータを取り出しながら格納していくため、リーフページは、FILLFACTORの割合で格納された状態で作成されます。

FILLFACTOR設定後にB-treeインデックスを生成した例

図15 FILLFACTOR設定後にB-treeインデックスを生成した例

そのため、格納するデータの特徴に合わせてFILLFACTORの値を調整することが推奨されます。例えば、IDとして1,2,3と順番に割り振るようなカラムデータに対するインデックスで、INSERTしか実施しない場合(UPDATEしない場合)は、FILLFACTORは100に設定しても問題ありません。しかし、名前のようにデータの並び順がランダムなカラムに対するインデックスであれば、FILLFACTORを設定してINSERT時の空きスペースを始めから作っておくことで、リーフページの分割を起きにくくします。また、UPDATE時にHOTの更新が働かず、インデックスの更新が発生する場合においても、インデックスの空きスペースを作成しておくことでリーフページの分割を抑えられる効果があります。

2.3 大量データは一括/並列で格納する

データを高速に格納するための方法について説明します。

大量データはCOPYコマンドで格納する

大量データを挿入する場合には、INSERT文で実施するよりもCOPYコマンドにより一括で格納する方が高速に格納できます。

多重実行でデータを格納する

INSERTやCOPYコマンドを1多重で実施して、データを格納していると、システムのリソースが余っていることがあります。その場合には、INSERTやCOPYコマンドを多重実行することで、ディスクI/Oなどのシステムリソースを有効に使い、パフォーマンスの改善が期待できます。多重度を決める際、実際の運用時と同じ状況で試行し、ディスクI/O(Linuxの場合はiostatコマンドなど)やCPU使用率(Linuxの場合はmpstatコマンドなど)を確認し、ボトルネックになる直前まで多重度を上げていきます。

参考

FUJITSU Software Enterprise Postgres」には、高速データロードのコマンドがあります。これは、COPYコマンド処理をパラレルワーカーにより並列に処理します。その際の多重度は、コマンドのパラメーターで指定します。また、独自システムビュー「pgx_stat_lwlock」を参照して内部の軽量ロック(注4)の状態から、待ちが発生しているかどうかの確認を行うこともできます。内部の軽量ロックで待ちの時間が多い場合、その処理でボトルネックになっていることが確認できます。

  • 注4
    軽量ロックは、共有メモリー内の特定のデータ構造を保護するために提供される排他機構です。開発者向けオプション trace_lwlocks = on で軽量ロックの使用状況に関する情報がログファイルに出力されます。なお、このパラメーターはPostgreSQLがコンパイル時にLOCK_DEBUGマクロが定義された場合のみ有効です。

PostgreSQLのパフォーマンスチューニングの一番重要なポイントである「書き」についての考え方と手法について解説しました。次回は、「探し」をテーマに解説します。

2022年3月25日更新

オンデマンド(動画)セミナー

    • PostgreSQLに関連するセミナー動画を公開中。いつでもセミナーをご覧いただけます。
      • 【事例解説】運送業務改革をもたらす次世代の運送業界向けDXプラットフォームの構築
      • ハイブリッドクラウドに最適なOSSベースのデータベースご紹介

本コンテンツに関するお問い合わせ

お電話でのお問い合わせ

Webでのお問い合わせ

当社はセキュリティ保護の観点からSSL技術を使用しております。

ページの先頭へ