パフォーマンスは、データベースを管理する際の最も重要で最も複雑なタスクの1つです。構成、ハードウェア、さらにはシステムの設計によっても影響を受ける可能性があります。デフォルトでは、パフォーマンスはハードウェアとシステム自体に大きく依存するため、PostgreSQLは互換性と安定性を念頭に置いて構成されています。大量のデータを読み取るシステムにすることはできますが、情報が頻繁に変わることはありません。または、継続的に書き込むシステムを作成することもできます。このため、すべてのタイプのワークロードで機能するデフォルト構成を定義することは不可能です。
このブログでは、実行中のワークロードまたはクエリを分析する方法を説明します。次に、PostgreSQLデータベースのパフォーマンスを向上させるために、いくつかの基本的な構成パラメーターを確認します。前述したように、一部のパラメーターのみが表示されます。 PostgreSQLパラメータのリストは広範であり、重要なもののいくつかにのみ触れます。ただし、いつでも公式ドキュメントを参照して、環境で最も重要または有用と思われるパラメータと構成を調べることができます。
説明
データベースのパフォーマンスを向上させる方法を理解するために実行できる最初のステップの1つは、行われたクエリを分析することです。
PostgreSQLは、受信するクエリごとにクエリプランを考案します。この計画を確認するには、EXPLAINを使用します。
クエリプランの構造は、プランノードのツリーです。ツリーの下位レベルのノードはスキャンノードです。テーブルから生の行を返します。テーブルにアクセスするさまざまな方法には、さまざまなタイプのスキャンノードがあります。 EXPLAIN出力には、プランツリーの各ノードの行があります。
world=# EXPLAIN SELECT * FROM city t1,country t2 WHERE id>100 AND t1.population>700000 AND t2.population<7000000;
QUERY PLAN
--------------------------------------------------------------------------
Nested Loop (cost=0.00..734.81 rows=50662 width=144)
-> Seq Scan on city t1 (cost=0.00..93.19 rows=347 width=31)
Filter: ((id > 100) AND (population > 700000))
-> Materialize (cost=0.00..8.72 rows=146 width=113)
-> Seq Scan on country t2 (cost=0.00..7.99 rows=146 width=113)
Filter: (population < 7000000)
(6 rows)
このコマンドは、クエリ内のテーブルがどのようにスキャンされるかを示します。 EXPLAINで観察できるこれらの値が何に対応するかを見てみましょう。
- 最初のパラメーターは、このステップでエンジンがデータに対して実行している操作を示します。
- 推定初期費用。これは、出力フェーズを開始する前に費やした時間です。
- 推定総費用。これは、プランノードが完了するまで実行されることを前提としています。実際には、ノードの親ノードは、使用可能なすべての行を読み取ることができない場合があります。
- このプランノードによって出力される推定行数。この場合も、ノードは最後まで実行されると想定されます。
- このプランノードによって出力される行の推定平均幅。
表示の最も重要な部分は、ステートメント実行コストの見積もりです。これは、ステートメントの実行にかかる時間に関するプランナーの推測です。あるクエリが他のクエリに対してどれほど効果的であるかを比較するとき、実際にはそれらのコスト値を比較します。
上位レベルのノードのコストには、そのすべての子ノードのコストが含まれることを理解することが重要です。コストはプランナーが気にかけていることだけを反映していることを理解することも重要です。特に、コストは、結果行をクライアントに送信するために費やされた時間を考慮していません。これは、実際の経過時間の重要な要素になる可能性があります。ただし、プランを変更して変更することはできないため、プランナーはそれを無視します。
コストは、プランナーのコストパラメーターによって決定される任意の単位で測定されます。従来の方法は、ディスクページフェッチの単位でコストを測定することです。つまり、seq_page_costは通常1.0に設定され、他のコストパラメータはそれに関連して設定されます。
EXPLAIN ANALYZE
このオプションを使用すると、EXPLAINはクエリを実行し、各プランノード内で累積された実際の行数と実際の実行時間を、プレーンなEXPLAINが示すのと同じ見積もりとともに表示します。
このツールの使用例を見てみましょう。
world=# EXPLAIN ANALYZE SELECT * FROM city t1,country t2 WHERE id>100 AND t1.population>700000 AND t2.population<7000000;
QUERY PLAN
----------------------------------------------------------------------------------------------------------------------
Nested Loop (cost=0.00..734.81 rows=50662 width=144) (actual time=0.081..22.066 rows=51100 loops=1)
-> Seq Scan on city t1 (cost=0.00..93.19 rows=347 width=31) (actual time=0.069..0.618 rows=350 loops=1)
Filter: ((id > 100) AND (population > 700000))
Rows Removed by Filter: 3729
-> Materialize (cost=0.00..8.72 rows=146 width=113) (actual time=0.000..0.011 rows=146 loops=350)
-> Seq Scan on country t2 (cost=0.00..7.99 rows=146 width=113) (actual time=0.007..0.058 rows=146 loops=1)
Filter: (population < 7000000)
Rows Removed by Filter: 93
Planning time: 0.136 ms
Execution time: 24.627 ms
(10 rows)
クエリに必要以上に時間がかかる理由が見つからない場合は、このブログで詳細を確認できます。
バキューム
VACUUMプロセスは、データベース内のいくつかの保守タスクを担当し、そのうちの1つは、デッドタプルによって占有されているストレージを回復します。 PostgreSQLの通常の操作では、更新によって削除または廃止されたタプルは、テーブルから物理的に削除されません。それらは、VACUUMが実行されるまで存在し続けます。したがって、特に頻繁に更新されるテーブルでは、定期的にVACUUMを実行する必要があります。
VACUUMに時間がかかりすぎたり、リソースが多すぎたりする場合は、より頻繁に実行する必要があることを意味します。これにより、各操作のクリーニングが少なくなります。
いずれの場合も、たとえば大量のデータをロードする場合など、VACUUMを無効にする必要がある場合があります。
VACUUMは単にスペースを回復し、再利用できるようにします。この形式のコマンドは、排他ロックが取得されないため、テーブルの通常の読み取りおよび書き込みと並行して動作できます。ただし、追加のスペースはオペレーティングシステムに返されません(ほとんどの場合)。同じテーブル内でのみ再利用できます。
VACUUM FULLは、追加のスペースなしでテーブルのすべての内容を新しいディスクファイルに再書き込みします。これにより、未使用のスペースをオペレーティングシステムに戻すことができます。この形式ははるかに遅く、処理中に各テーブルを排他的にロックする必要があります。
VACUUM ANALYZEは、選択されたテーブルごとにVACUUMを実行してからANALYZEを実行します。これは、定期的なメンテナンススクリプトを組み合わせる実用的な方法です。
ANALYZEは、データベース内のテーブルの内容に関する統計を収集し、その結果をpg_statisticに格納します。その後、クエリプランナーはこれらの統計を使用して、クエリの最も効率的な実行プランを決定します。
今日のホワイトペーパーをダウンロードするClusterControlを使用したPostgreSQLの管理と自動化PostgreSQLの導入、監視、管理、スケーリングを行うために知っておくべきことについて学ぶホワイトペーパーをダウンロードする構成パラメーター
これらのパラメータを変更するには、ファイル$ PGDATA/postgresql.confを編集する必要があります。それらのいくつかはデータベースの再起動を必要とすることを覚えておく必要があります。
max_connections
データベースへの同時接続の最大数を決定します。クライアントごとに構成できるメモリリソースがあるため、クライアントの最大数は、使用されるメモリの最大量を示唆する可能性があります。
superuser_reserved_connections
max_connectionの制限に達した場合、これらの接続はスーパーユーザー用に予約されています。
shared_buffers
データベースサーバーが共有メモリバッファに使用するメモリの量を設定します。 1 GB以上のRAMを備えた専用データベースサーバーがある場合、shared_buffersの妥当な初期値はシステムのメモリの25%です。 shared_buffersの構成を大きくするには、通常、max_wal_sizeを対応して増やす必要があります。これにより、大量の新規または変更されたデータを長期間にわたって書き込むプロセスが拡張されます。
temp_buffers
各セッションで使用される一時バッファの最大数を設定します。これらは、一時テーブルにアクセスするためにのみ使用されるローカルセッションバッファです。セッションは、temp_buffersで指定された制限まで、必要に応じて一時バッファを割り当てます。
work_mem
ディスク上の一時ファイルに書き込む前に、ORDER BY、DISTINCT、JOIN、およびハッシュテーブルの内部操作で使用されるメモリの量を指定します。この値を構成するときは、複数のセッションがこれらの操作を同時に実行していることを考慮する必要があります。各操作は、一時ファイルへのデータの書き込みを開始する前に、この値で指定された量のメモリを使用できます。
このオプションは、古いバージョンのPostgreSQLではsort_memと呼ばれていました。
maintenance_work_mem
VACUUM、CREATE INDEX、ALTER TABLE ADD FOREIGN KEYなど、保守操作が使用するメモリーの最大量を指定します。これらの操作の1つだけがセッションによって同時に実行でき、インストールでは通常、それらの多くが同時に実行されないため、work_memよりも大きくなる可能性があります。構成を大きくすると、VACUUMとデータベースの復元のパフォーマンスが向上します。
autovacuumが実行されるとき、このメモリにはautovacuum_max_workersパラメータが設定された回数を割り当てることができるため、これを考慮する必要があります。そうでない場合は、autovacuum_work_memパラメータを設定してこれを個別に管理します。
fsync
fsyncが有効になっている場合、PostgreSQLは更新が物理的にディスクに書き込まれていることを確認しようとします。これにより、オペレーティングシステムまたはハードウェアがクラッシュした後でも、データベースクラスターを一貫した状態に復元できます。
通常、fsyncを無効にするとパフォーマンスが向上しますが、電源障害やシステムクラッシュが発生した場合にデータが失われる可能性があります。したがって、外部データからデータベース全体を簡単に再作成できる場合にのみ、fsyncを非アクティブ化することをお勧めします。
checkpoint_segments(PostgreSQL <9.5)
自動WAL制御ポイント間のレコードファイルセグメントの最大数(各セグメントは通常16メガバイトです)。このパラメーターを増やすと、障害の回復に必要な時間が長くなる可能性があります。トラフィックの多いシステムでは、非常に低い値に設定すると、パフォーマンスに影響を与える可能性があります。多くのデータ変更があるシステムでは、checkpoint_segmentsの値を増やすことをお勧めします。
また、WALファイルをPGDATA以外のディスクに保存することをお勧めします。これは、書き込みのバランスをとる場合と、ハードウェア障害が発生した場合のセキュリティの両方に役立ちます。
PostgreSQL 9.5以降、構成変数「checkpoint_segments」は削除され、「max_wal_size」と「min_wal_size」に置き換えられました
max_wal_size(PostgreSQL> =9.5)
WALがコントロールポイント間で拡大できる最大サイズ。特別な状況では、WALのサイズがmax_wal_sizeを超える場合があります。このパラメータを増やすと、障害の回復に必要な時間が長くなる可能性があります。
min_wal_size(PostgreSQL> =9.5)
WALファイルがこの値を下回っている場合、削除されるのではなく、チェックポイントで将来使用するためにリサイクルされます。これを使用して、たとえば大規模なバッチジョブを実行する場合など、WALの使用におけるスパイクを処理するために十分なWALスペースを確保することができます。
wal_sync_method
WALの更新をディスクに強制するために使用される方法。 fsyncが無効になっている場合、この設定は効果がありません。
wal_buffers
まだディスクに書き込まれていないWALデータに使用される共有メモリの量。デフォルト設定は、shared_buffersの約3%であり、64KB以上またはWALセグメントのサイズ(通常は16MB)を超えています。この値を少なくとも数MBに設定すると、同時トランザクションが多いサーバーでの書き込みパフォーマンスを向上させることができます。
effective_cache_size
この値は、メモリに収まる場合と収まらない場合があるプランを考慮に入れるためにクエリプランナーによって使用されます。これは、インデックスを使用する場合のコスト見積もりで考慮されます。値が高いとインデックススキャンが使用される可能性が高くなり、値が低いとシーケンシャルスキャンが使用される可能性が高くなります。妥当な値はRAMの50%です。
default_statistics_target
PostgreSQLは、データベース内の各テーブルから統計を収集して、クエリがそれらに対してどのように実行されるかを決定します。デフォルトでは、あまり多くの情報を収集しません。適切な実行計画が得られない場合は、この値を増やしてから、データベースでANALYZEを再度実行する必要があります(またはAUTOVACUUMを待ちます)。
synchronous_commit
コマンドがクライアントに「成功」表示を返す前に、トランザクションコミットがWALレコードがディスクに書き込まれるのを待機するかどうかを指定します。可能な値は、「on」、「remote_apply」、「remote_write」、「local」、「off」です。デフォルト設定は「オン」です。無効にすると、クライアントが戻ってからトランザクションがサーバーロックに対して安全であることが保証されるまでに遅延が発生する可能性があります。 fsyncとは異なり、このパラメーターを無効にしても、データベースの不整合のリスクは発生しません。オペレーティングシステムまたはデータベースがクラッシュすると、コミットされたとされる最近のトランザクションが失われる可能性がありますが、データベースの状態は、それらのトランザクションとまったく同じになります。きれいにキャンセルされました。したがって、synchronous_commitを非アクティブ化することは、トランザクションの耐久性に関する正確な確実性よりもパフォーマンスが重要な場合に役立つ代替手段になる可能性があります。
ロギング
ログに記録するデータには、役立つかどうかわからないものがいくつかあります。それらのいくつかを見てみましょう:
- log_min_error_statement:最小ログレベルを設定します。
- log_min_duration_statement:システムで遅いクエリを記録するために使用されます。
- log_line_prefix:各ログ行の先頭に情報を添付します。
- log_statement:NONE、DDL、MOD、ALLから選択できます。 「すべて」を使用すると、パフォーマンスの問題が発生する可能性があります。
デザイン
多くの場合、データベースの設計がパフォーマンスに影響を与える可能性があります。設計では注意が必要であり、スキーマを正規化し、冗長なデータを回避する必要があります。多くの場合、1つの大きなテーブルではなく、複数の小さなテーブルがあると便利です。しかし、前に述べたように、すべてがシステムに依存しており、考えられる解決策は1つではありません。
また、責任を持ってインデックスを使用する必要があります。テーブル全体を移動する必要はありませんが、ディスクスペースを使用し、書き込み操作にオーバーヘッドを追加しているため、各フィールドまたはフィールドの組み合わせに対してインデックスを作成しないでください。
もう1つの非常に便利なツールは、接続プールの管理です。負荷の高いシステムがある場合は、これを使用して、データベース内の接続が飽和状態になるのを防ぎ、それらを再利用できるようにすることができます。
ハードウェア
このブログの冒頭で述べたように、ハードウェアはデータベースのパフォーマンスに直接影響する重要な要素の1つです。覚えておくべきいくつかのポイントを見てみましょう。
- メモリ:RAMが多いほど、処理できるメモリデータが多くなり、パフォーマンスが向上します。ディスクでの書き込みと読み取りの速度はメモリよりもはるかに遅いため、メモリに保持できる情報が多いほど、パフォーマンスが向上します。
- CPU:これを言うのはあまり意味がないかもしれませんが、CPUが多ければ多いほど良いでしょう。いずれにせよ、ハードウェアの観点からは最も重要ではありませんが、優れたCPUを使用できれば、処理能力が向上し、データベースに直接影響します。
- ハードディスク:使用できるディスクには、SCSI、SATA、SAS、IDEなどがあります。ソリッドステートディスクもあります。速度を比較するために使用する必要がある品質/価格を比較する必要があります。ただし、考慮すべきのはディスクの種類だけではありません。ディスクの構成方法も確認する必要があります。良好なパフォーマンスが必要な場合は、RAID10を使用して、WALをRAID外の別のディスクに保持できます。このタイプのデータベース用RAIDのパフォーマンスは良くないため、RAID5の使用はお勧めしません。
結論
このブログで言及されている点を考慮した後、データベースの動作を検証するためのベンチマークを実行できます。
また、データベースを監視して、パフォーマンスの問題に直面しているかどうかを判断し、できるだけ早く解決できるようにすることも重要です。このタスクには、Nagios、ClusterControl、Zabbixなどのいくつかのツールがあり、監視するだけでなく、それらのいくつかを使用して、問題が発生する前に予防的なアクションを実行できます。 ClusterControlを使用すると、監視、管理、およびその他のいくつかのユーティリティに加えて、パフォーマンスアラートを受信するときに実行できるアクションに関する推奨事項を受け取ることができます。これにより、潜在的な問題を解決する方法を知ることができます。
このブログは、データベースのパフォーマンスを向上させる方法を網羅したガイドとなることを目的としたものではありません。うまくいけば、それは何が重要になることができるか、そして設定できるいくつかの基本的なパラメータのより明確な絵を与えるでしょう。重要なものを見逃した場合は、遠慮なくお知らせください。