PostgreSQLは世界で最も人気のあるオープンソースデータベースの1つであり、1日に数百万から数十億のトランザクションを実行するリアルタイムのハイエンドOLTPアプリケーションを使用して、さまざまなドメインのいくつかのミッションクリティカルな環境で実装に成功しています。 PostgreSQL I / Oは非常に信頼性が高く、安定しており、クラウドを含むほとんどすべてのハードウェアでパフォーマンスが向上します。
データベースが期待される応答時間で期待される規模で動作することを保証するには、パフォーマンスエンジニアリングが必要です。さて、優れたデータベースパフォーマンスの達成は、さまざまな要因に依存します。データベースのパフォーマンスは、インフラストラクチャのディメンション化、非効率的なデータベースメンテナンス戦略、不十分なSQLコード、またはCPU、メモリ、ネットワーク帯域幅、ディスクI / Oなどの利用可能なすべてのリソースを利用できない不適切に構成されたデータベースプロセスなど、さまざまな理由で悪化する可能性があります。
>データベースのパフォーマンスが低下する原因は何ですか?
- CPUとメモリを大量に消費する結合やロジックなどが不適切に記述されたクエリ
- 不適切なインデックス作成のために大きなテーブルで全表スキャンを実行するクエリ
- 適切な統計がない状態でのデータベースのメンテナンスが悪い
- キャパシティプランニングが非効率的であるため、インフラストラクチャのディメンションが不適切になります
- 不適切な論理的および物理的設計
- 接続プールが設定されていないため、アプリケーションが制御不能な方法で膨大な数の接続を確立します。
つまり、パフォーマンスの問題を引き起こす可能性のある多くの潜在的な領域です。このブログで焦点を当てたい重要な領域の1つは、PostgreSQL I / O(入力/出力)のパフォーマンスを調整する方法です。 PostgreSQLの入出力操作の調整は、特にOLTPのようなトランザクションの多い環境や、巨大なサイズのデータセットで複雑なデータ分析を行うデータウェアハウス環境では不可欠です。
ほとんどの場合、データベースのパフォーマンスの問題は、主にI/Oが高いことが原因で発生します。これは、データベースプロセスがディスクへの書き込みまたはディスクからの読み取りに多くの時間を費やしていることを意味します。リアルタイムのデータ操作はすべてI/Oバウンドであるため、データベースがI/O調整されていることを確認する必要があります。このブログでは、PostgreSQLデータベースがリアルタイムの実稼働環境で遭遇する可能性のある一般的なI/Oの問題に焦点を当てます。
PostgreSQL I/Oの調整
PostgreSQL I / Oの調整は、高性能でスケーラブルなデータベースアーキテクチャを構築するために不可欠です。 I/Oパフォーマンスに影響を与えるさまざまな要因を見てみましょう。
- インデックス作成
- パーティショニング
- チェックポイント
- 真空、分析(FILLFACTORを使用)
- その他のI/Oの問題
- クラウド上のPostgreSQLI/ O
- ツール
インデックス作成
インデックス作成は、データベースI/Oのパフォーマンスを向上させる上で不可欠な役割を果たすコアチューニング手法の1つです。これは実際にはどのデータベースにも当てはまります。 PostgreSQLはさまざまなインデックスタイプをサポートしており、読み取り操作を大幅に高速化して、アプリケーションのスケーラビリティを向上させることができます。インデックスの作成は非常に単純で簡単ですが、DBAと開発者は、選択するインデックスのタイプと列についての知識を持っていることが不可欠です。後者は、クエリの複雑さ、データタイプ、データカーディナリティ、書き込み量、データサイズ、ディスクアーキテクチャ、インフラストラクチャ(パブリッククラウド、プライベートクラウド、またはオンプレミス)などのさまざまな要因に基づいています。
インデックス付けはクエリの読み取りパフォーマンスを劇的に向上させることができますが、インデックス付けされた列にヒットする書き込みを遅くすることもできます。例を見てみましょう:
READ操作に対するインデックスの影響
約100万行のempというテーブル。
インデックスなしのREADパフォーマンス
postgres=# select * from emp where eid=10;
eid | ename | peid | did | doj
-----+---------------+--------+------+------------
10 | emp | | 1 | 2018-06-06
(1 row)
Time: 70.020 ms => took about 70+ milli-seconds to respond with on row
インデックスを使用したパフォーマンスの読み取り
eid列にインデックスを付けて、違いを確認しましょう
postgres=# create index indx001 on emp ( eid );
CREATE INDEX
postgres=# select * from emp where eid=10;
eid | ename | peid | did | doj
------+-------------+-------+------+------------
10 | emp | | 1 | 2018-06-06
(1 row)
Time: 0.454 ms => 0.4+ milli-seconds!!! thats a huge difference - isn’t it?
したがって、インデックス作成は重要です。
書き込み操作に対するインデックスの影響
インデックスは書き込みのパフォーマンスを低下させます。インデックスはすべてのタイプの書き込み操作に影響を与えますが、INSERTへのインデックスの影響に関する分析を見てみましょう
インデックスなしのテーブルに100万行を挿入
postgres=# do $$
postgres$# declare
postgres$# i integer;
postgres$# begin
postgres$# for i in 1..1000000 loop
postgres$# insert into emp values (i,'emp',null,1,current_date);
postgres$# end loop;
postgres$# end $$;
DO
Time: 4818.470 ms (00:04.818) => Takes about 4.8 seconds
同じ100万行をインデックスで挿入
最初にインデックスを作成しましょう
postgres=# create index indx001 on emp ( eid );
CREATE INDEX
postgres=# do $$
postgres$# declare
postgres$# i integer;
postgres$# begin
postgres$# for i in 1..1000000 loop
postgres$# insert into emp values (i,'emp',null,1,current_date);
postgres$# end loop;
postgres$# end $$;
DO
Time: 7825.494 ms (00:07.825) => Takes about 7.8 seconds
したがって、観察できるように、INSERT時間は1つのインデックスだけで80%増加し、複数のインデックスがある場合は終了までにはるかに長い時間がかかる可能性があります。関数ベースのインデックスがある場合は、さらに悪化する可能性があります。それがDBAが一緒に暮らさなければならないことです!インデックスを使用すると、書き込みパフォーマンスが向上します。ただし、この問題に取り組む方法はいくつかありますが、これはディスクアーキテクチャに依存します。データベースサーバーが複数のディスクファイルシステムを使用している場合、インデックスとテーブルは、複数のディスクファイルシステムにまたがる複数のテーブルスペースに配置できます。このようにして、より優れたI/Oパフォーマンスを実現できます。
インデックス管理のヒント
- インデックスの必要性を理解します。インテリジェントなインデックス作成が重要です。
- 複数のインデックスを作成することは避けてください。不要なインデックスを作成しないでください。これにより、書き込みパフォーマンスが大幅に低下する可能性があります。
- インデックスの使用状況を監視し、未使用のインデックスを削除します。
- インデックス付きの列がデータ変更の対象になると、インデックスも肥大化します。そのため、定期的にインデックスを再編成してください。
パーティショニング
効果的なパーティショニング戦略により、I/Oパフォーマンスの問題を大幅に減らすことができます。大きなテーブルは、ビジネスロジックに基づいて分割できます。 PostgreSQLはテーブルパーティショニングをサポートしています。現時点ではすべての機能を完全にサポートしているわけではありませんが、リアルタイムのユースケースの一部にしか役立ちません。 PostgreSQLでは、パーティション化された子テーブルは、ボトルネックであるマスターテーブルに対して完全に個別です。たとえば、マスターテーブルで作成された制約は、子テーブルに自動的に継承できません。
ただし、I / Oのバランスをとる観点からは、パーティショニングが非常に役立ちます。すべての子パーティションは、複数のテーブルスペースとディスクファイルシステムに分割できます。テーブルにヒットする「where」句に日付範囲があり、日付範囲に基づいてパーティション化されたクエリは、テーブル全体ではなく1つまたは2つのパーティションをスキャンするだけで、パーティション化のメリットを享受できます。
チェックポイント
チェックポイントは、データベースの一貫性のある状態を定義します。これらは重要であり、データの変更がディスクに永続的に保存され、データベースが常に一貫した状態にあることを保証するために、チェックポイントが定期的に発生することが重要です。そうは言っても、チェックポイントの不適切な構成はI/Oパフォーマンスの問題につながる可能性があります。 DBAは、I / Oスパイクがないことを確認するためにチェックポイントの構成に細心の注意を払う必要があります。また、これは、ディスクの品質とデータファイルレイアウトの設計の程度によって異なります。
チェックポイントは何をしますか?
簡単に言うと、チェックポイントによって次のことが保証されます。
- コミットされたすべてのデータは、ディスク上のデータファイルに書き込まれます。
- clogファイルはコミットステータスで更新されます。
- pg_xlog(現在はpg_wal)ディレクトリ内のトランザクションログファイルはリサイクルされます。
これは、I/O集中チェックポイントがどのようになっているのかを説明しています。 postgresql.confには、チェックポイントの動作を制御するように構成/調整できるパラメーターがあり、それらのパラメーターはmax_wal_size、min_wal_size、checkpoint_timeout、およびcheckpoint_completion_targetです。これらのパラメータは、チェックポイントが発生する頻度と、チェックポイントが終了する必要がある時間内に決定します。
チェックポイントに適した構成を理解するにはどうすればよいですか?それらを調整する方法は?
ここにいくつかのヒントがあります:
- データベースTPSを評価します。 1営業日にデータベースで発生するトランザクションの総量を評価し、データベースにヒットするトランザクションの最大数を特定します。
- アプリケーション開発者や他の技術チームと定期的に話し合い、データベースのトランザクション率の統計と将来のトランザクションの増加を理解します。
- これはデータベース側からも実行できます:
-
データベースを監視し、その日に発生したトランザクションの数を評価します。これは、pg_stat_user_tablesなどのpgcatalogテーブルをクエリすることで実行できます。
-
1日に生成されるwalアーカイブファイルの数を評価する
-
log_checkpointsパラメータを有効にして、チェックポイントのパフォーマンスを監視します
2018-06-06 15:03:16.446 IST [2111] LOG: checkpoint starting: xlog 2018-06-06 15:03:22.734 IST [2111] LOG: checkpoint complete: wrote 12112 buffers (73.9%); 0 WAL file(s) added, 0 removed, 25 recycled; write=6.058 s, sync=0.218 s, total=6.287 s; sync files=4, longest=0.178 s, average=0.054 s; distance=409706 kB, estimate=412479 kB
-
現在のチェックポイント構成がデータベースに十分であるかどうかを理解します。 checkpoint_warningパラメーターを構成して(デフォルトでは30秒に構成されています)、postgresログファイルに以下の警告を表示します。
2018-06-06 15:02:42.295 IST [2111] LOG: checkpoints are occurring too frequently (11 seconds apart) 2018-06-06 15:02:42.295 IST [2111] HINT: Consider increasing the configuration parameter "max_wal_size".
-
上記の警告はどういう意味ですか?
チェックポイントは通常、max_wal_size(デフォルトでは1 GB、つまり64 WALファイル)に相当するログファイルがいっぱいになるか、checkpoint_timeout(デフォルトごとに5分ごと)に達すると発生します。上記の警告は、構成されたmax_wal_sizeが適切でなく、チェックポイントが11秒ごとに発生していることを意味します。つまり、PG_WALディレクトリ内の64個のWALファイルがわずか11秒でいっぱいになることを意味します。つまり、トランザクションの頻度が少ない場合、チェックポイントは5分ごとに発生します。したがって、ヒントが示すように、max_wal_sizeパラメーターをより高い値に増やすと、max_min_sizeパラメーターを以前と同じかそれより小さくすることができます。
I / Oパフォーマンスの観点から考慮すべきもう1つの重要なパラメーターは、デフォルトで0.5に構成されているcheckpoint_completion_targetです。
checkpoint_completion_target =0.5 x checkpoint_timeout=2.5分
つまり、チェックポイントはダーティブロックをディスクに同期するのに2.5分かかります。 2.5分で十分ですか?それを評価する必要があります。書き込まれるダーティブロックの数が非常に多い場合、2.5分は非常に攻撃的に見える可能性があり、そのときにI/Oスパイクが観察されます。 complete_targetパラメーターの構成は、max_wal_size値とcheckpoint_timeout値に基づいて行う必要があります。これらのパラメータをより高い値に上げる場合は、それに応じてcheckpoint_completion_targetを上げることを検討してください。
真空、分析(フィルファクター付き)
VACUUMは、PostgreSQLの最も強力な機能の1つです。これは、テーブルおよびインデックス内の膨張(断片化されたスペース)を削除するために使用でき、トランザクションによって生成されます。健全なメンテナンスとパフォーマンスの向上を確実にするために、データベースは定期的にVACUUMingにかけられる必要があります。繰り返しになりますが、データベースを定期的にVACUUMしないと、深刻なパフォーマンスの問題が発生する可能性があります。クエリプランナーの最新の統計を確認するには、ANALYZEをVACUUM(VACUUM ANALYZE)と一緒に実行する必要があります。
VACUUM ANALYZEは、手動、自動、またはその両方の2つの方法で実行できます。リアルタイムの実稼働環境では、通常は両方です。自動VACUUMは、デフォルトで「オン」に設定されているパラメータ「autovacuum」によって有効になります。自動バキュームを有効にすると、PostgreSQLは自動的にテーブルのバキュームを定期的に開始します。真空引きが必要な候補テーブルは、さまざまな自動真空*パラメータによって設定されたさまざまなしきい値に基づいて自動真空プロセスによってピックアップされます。これらのパラメータは、テーブルの膨張が定期的にクリアされるように微調整/調整できます。いくつかのパラメータとその使用法を見てみましょう-
自動真空パラメータ
autovacuum =on | このパラメータは、自動真空を有効/無効にするために使用されます。デフォルトは「オン」です。 |
log_autovacuum_min_duration =-1 | 自動真空プロセスの期間をログに記録します。これは、自動真空プロセスが実行されていた時間を理解するために重要です。 |
autovacuum_max_workers =3 | 必要な自動真空プロセスの数。これは、データベーストランザクションがどれほど積極的であるか、および自動真空プロセスに提供できるCPUの数によって異なります。 |
autovacuum_naptime=1分 | 自動真空実行間の自動真空休止時間。 |
自動真空プロセスを開始するためのしきい値を定義するパラメーター
自動真空ジョブは、特定のしきい値に達すると開始されます。以下は、特定のしきい値を設定するために使用できるパラメータであり、それに基づいて自動真空プロセスが開始されます。
autovacuum_vacuum_threshold =50 | テーブル内で最低50行が更新/削除されると、テーブルはバキュームされます。 |
autovacuum_analyze_threshold =50 | テーブルで最低50行が更新/削除されると、テーブルが分析されます。 |
autovacuum_vacuum_scale_factor =0.2 | テーブル内の行の少なくとも20%が更新/削除されると、テーブルはバキュームされます。 |
autovacuum_analyze_scale_factor =0.1 | テーブル内の行の少なくとも10%が更新/削除されると、テーブルはバキュームされます。 |
しきい値を超えるパラメーターは、データベースの動作に基づいて変更できます。 DBAは、ホットテーブルを分析および識別し、それらのテーブルが可能な限り頻繁にバキュームされていることを確認して、良好なパフォーマンスを確保する必要があります。これらのパラメータの特定の値に到達することは、データの変更が毎秒発生するトランザクションの多い環境では困難な場合があります。何度も、自動真空プロセスの完了に非常に長い時間がかかり、本番システムで大量のリソースを消費することになります。
自動バキュームプロセスに完全に依存しないことをお勧めします。自動バキュームの負担を軽減するために、夜間のVACUUMANALYZEジョブをスケジュールするのが最善の方法です。まず、トランザクション率の高い大きなテーブルを手動でVACUUMすることを検討してください。
バキュームフル
VACUUM FULLは、テーブルとインデックスの肥大化したスペースを再利用するのに役立ちます。このユーティリティは、データベースがオンラインの場合、テーブルをロックするため使用できません。テーブルは、アプリケーションがシャットダウンされている場合にのみVACUUMFULLにさらされる必要があります。 VACUUM FULL中に、インデックスもテーブルとともに再編成されます。
VACUUMANALYZEの影響を見てみましょう
膨張:膨張を識別する方法は?膨張はいつ発生しますか?
ここにいくつかのテストがあります:
サイズ1GB、1,000万行のテーブルがあります。
postgres=# select pg_relation_size('pgbench_accounts')/1024/1024/1024;
?column?
----------------
1
postgres=# select count(*) From pgbench_accounts ;
count
-----------------
10000000
単純なクエリに対する膨張の影響を見てみましょう:select * from pgbench_accounts;
以下は、クエリの説明プランです。
postgres=# explain analyze select * from pgbench_accounts;
QUERY PLAN
------------------------------------------------------------------------------------------------------------------------------------------------
Seq Scan on pgbench_accounts (cost=0.00..263935.00 rows=10000000 width=97)
(actual time=0.033..1054.257 rows=10000000 loops=1)
Planning time: 0.255 ms
Execution time: 1494.448 ms
次に、テーブル内のすべての行を更新して、上記のSELECTクエリの影響を確認しましょう。
postgres=# update pgbench_accounts set abalance=1;
UPDATE 10000000
postgres=# select count(*) From pgbench_accounts ;
count
-----------------
10000000
以下は、UPDATE実行後のクエリのEXPLAINPLANです。
postgres=# explain analyze select * from pgbench_accounts;
QUERY PLAN
----------------------------------------------------------------------------------------------------------------------------------------------------------
Seq Scan on pgbench_accounts (cost=0.00..527868.39 rows=19999939 width=97)
(actual time=404.474..1520.175 rows=10000000 loops=1)
Planning time: 0.051 ms
Execution time: 1958.532 ms
更新後、テーブルのサイズが2GBに増加しました
postgres=# select pg_relation_size('pgbench_accounts')/1024/1024/1024;
?column?
-----------------
2
以前のEXPLAINPLANのコスト数を観察して比較できれば、大きな違いがあります。コストは大幅に増加しました。さらに重要なことに、注意深く観察すると、UPDATE後にスキャンされる行数(1900万をわずかに超える)は、実際の既存の行(1000万)のほぼ2倍です。つまり、肥大化した行の数は900万を超え、実際の時間も増加し、実行時間は1.4秒から1.9秒に増加しました。
つまり、これは、UPDATE後にテーブルをVACUUMしないことの影響です。上記のEXPLAINPLAN番号は、正確にはテーブルが肥大化していることを意味します。
テーブルが肥大化しているかどうかを識別する方法は? pgstattuple contribモジュールを使用します:
postgres=# select * from pgstattuple('pgbench_accounts');
table_len | tuple_count | tuple_len | tuple_percent | dead_tuple_count | dead_tuple_len | dead_tuple_percent | free_space | free_percent
------------+-------------+------------+---------------+------------------+----------------+--------------------+------------+--------------
2685902848 | 10000000 | 1210000000 | 45.05 | 9879891 | 1195466811 | 44.51 | 52096468 | 1.94
上記の数値は、テーブルの半分が肥大化していることを示しています。
テーブルを真空分析して、今すぐ影響を確認しましょう:
postgres=# VACUUM ANALYZE pgbench_accounts ;
VACUUM
postgres=# explain analyze select * from pgbench_accounts;
QUERY PLAN
-----------------------------------------------------------------------------------------------------------------------------------------------
Seq Scan on pgbench_accounts (cost=0.00..428189.05 rows=10032005 width=97)
(actual time=400.023..1472.118 rows=10000000 loops=1)
Planning time: 4.374 ms
Execution time: 1913.541 ms
VACUUM ANALYZEの後、コスト数は減少しました。現在、スキャンされた行数は1,000万行近くになり、実際の時間と実行時間もそれほど変化していません。これは、テーブルの膨張がなくなったにもかかわらず、スキャンされるテーブルのサイズが同じままであるためです。以下は、VACUUMANALYZE後のpgstattuple出力です。
postgres=# select * from pgstattuple('pgbench_accounts');
table_len | tuple_count | tuple_len | tuple_percent | dead_tuple_count | dead_tuple_len | dead_tuple_percent | free_space | free_percent
------------+-------------+------------+---------------+------------------+----------------+--------------------+------------+--------------
2685902848 | 10000000 | 1210000000 | 45.05 | 0 | 0 | 0 | 1316722516 | 49.02
上記の数字は、すべての膨張(死んだタプル)が消えたことを示しています。
VACUUM FULL ANALYZEの影響を見て、何が起こるか見てみましょう:
postgres=# vacuum full analyze pgbench_accounts ;
VACUUM
postgres=# explain analyze select * from pgbench_accounts;
QUERY PLAN
---------------------------------------------------------------------------
Seq Scan on pgbench_accounts (cost=0.00..263935.35 rows=10000035 width=97)
(actual time=0.015..1089.726 rows=10000000 loops=1)
Planning time: 0.148 ms
Execution time: 1532.596 ms
観察すると、実際の時間と実行時間の数値は、UPDATE前の数値と同様です。また、テーブルのサイズが2GBから1GBに減少しました。
postgres=# select pg_relation_size('pgbench_accounts')/1024/1024/1024;
?column?
-----------------
1
それがVACUUMFULLの影響です。
フィルファクター
FILLFACTORは非常に重要な属性であり、テーブルおよびインデックスレベルでデータベースの保守戦略に実際の違いをもたらすことができます。この値は、データブロック内のINSERTによって使用されるスペースの量を示します。 FILLFACTOR値のデフォルトは100%です。これは、INSERTがデータブロックで使用可能なすべてのスペースを利用できることを意味します。また、UPDATEに使用できるスペースがないことも意味します。この値は、頻繁に更新されるテーブルの特定の値に減らすことができます。
このパラメーターは、各テーブルとインデックスに構成できます。 FILLFACTORが最適な値に構成されている場合、VACUUMのパフォーマンスとクエリのパフォーマンスにも実際の違いが見られます。つまり、最適なFILLFACTOR値により、不要な数のブロックが割り当てられなくなります。
上記の同じ例を見てみましょう-
テーブルには100万行あります
postgres=# select count(*) From pgbench_accounts ;
count
-----------------
10000000
更新前のテーブルのサイズは1GBです
postgres=# select pg_relation_size('pgbench_accounts')/1024/1024/1024;
?column?
--------
1
postgres=# update pgbench_accounts set abalance=1;
UPDATE 10000000
更新後、テーブルのサイズは更新後に2GBに増加しました
postgres=# select pg_relation_size('pgbench_accounts')/1024/1024/1024;
?column?
---------
2
つまり、テーブルに割り当てられるブロックの数が100%増加しました。 FILLFACTORが構成されている場合、テーブルのサイズはそのマージンだけ増加していない可能性があります。
FILLFACTORに設定する値を知る方法は?
これはすべて、更新される列と更新される列のサイズによって異なります。一般に、FILLFACTOR値は、UATデータベースでテストして評価するとよいでしょう。更新される列がテーブル全体の10%である場合は、fillfactorを90%または80%に構成することを検討してください。
重要な注意:
データを使用して既存のテーブルのFILLFACTOR値を変更する場合は、VACUUM FULLを実行するか、テーブルを再編成して、FILLFACTOR値が既存のデータに対して有効であることを確認する必要があります。
VACUUMING TIPS
- 上記のように、autovacuumが有効になっている場合でも、頻繁に使用されるテーブルでVACUUMANALYZEジョブを毎晩手動で実行することを検討してください。
- 一括INSERT後、テーブルでVACUUMANALYZEを実行することを検討してください。多くの人がINSERTの後にVACUUMingは必要ないかもしれないと信じているので、これは重要です。
- テーブルpg_stat_user_tablesにクエリを実行して、非常にアクティブなテーブルが定期的にVACUUMされていることを確認します。
- pg_stattuple contribモジュールを使用して、テーブルセグメント内の肥大化したスペースのサイズを特定します。
- VACUUM FULLユーティリティーは、実動データベース・システムでは使用できません。ロックなしでオンラインでテーブルとインデックスを再編成するのに役立つpg_reorgやpg_repackなどのツールの使用を検討してください。
- AUTOVACUUMプロセスが、営業時間(トラフィックが多い時間)に長時間実行されるようにします。
- log_autovacuum_min_durationパラメータを有効にして、AUTOVACUUMプロセスのタイミングと期間をログに記録します。
- 重要なのは、トランザクションの多いテーブルとインデックスでFILLFACTORが最適な値に構成されていることを確認することです。
その他のI/Oの問題
ディスクの並べ替え
並べ替えを実行するクエリは、リアルタイムの本番データベースでよく発生するもう1つの問題であり、これらのほとんどは回避できません。 GROUP BY、ORDER BY、DISTINCT、CREATE INDEX、VACUUM FULLなどの句を使用したクエリは並べ替えを実行し、並べ替えはディスク上で実行できます。インデックス付きの列に基づいて選択と並べ替えが行われる場合、並べ替えはメモリ内で行われます。ここで、複合インデックスが重要な役割を果たします。インデックスは積極的にメモリにキャッシュされます。そうしないと、ディスク上のデータを並べ替える必要が生じた場合、パフォーマンスが大幅に低下します。
ソートがメモリ内で確実に行われるようにするために、work_memパラメーターを使用できます。このパラメーターは、ソート全体をメモリー内で実行できるような値に構成できます。このパラメーターの主な利点は、postgresql.confで構成する以外に、セッションレベル、ユーザーレベル、またはデータベースレベルで構成できることです。 work_memの値はどのくらいにする必要がありますか?どのクエリがディスクソートを実行しているかを知る方法は?リアルタイムの本番データベースでディスクソートを実行するクエリを監視するにはどうすればよいですか?
答えは、log_temp_filesパラメーターを特定の値に構成することです。値はバイト単位で、値0は、ディスクの並べ替えのためにディスク上に生成されたすべての一時ファイル(およびそれらのサイズ)をログに記録します。パラメータを設定すると、ログファイルに次のメッセージが表示されるようになります
2018-06-07 22:48:02.358 IST [4219] LOG: temporary file: path "base/pgsql_tmp/pgsql_tmp4219.0", size 200425472
2018-06-07 22:48:02.358 IST [4219] STATEMENT: create index bid_idx on pgbench_accounts(bid);
2018-06-07 22:48:02.366 IST [4219] LOG: duration: 6421.705 ms statement: create index bid_idx on pgbench_accounts(bid);
上記のメッセージは、CREATE INDEXクエリがディスクの並べ替えを実行していて、サイズが200425472バイトの191+MBのファイルを生成したことを意味します。つまり、この特定のクエリでメモリソートを実行するには、work_memパラメータを191MB以上に設定する必要があります。
アプリケーションクエリの場合、work_memパラメーターはユーザーレベルでのみ構成できます。その前に、ユーザーがデータベースに対して行っている接続の数と、そのユーザーによって実行されている並べ替えクエリの数に注意してください。 PostgreSQLは各接続の各プロセスにwork_memを割り当てようとするため(ソートを実行)、データベースサーバーのメモリが不足する可能性があります。
データベースファイルシステムのレイアウト
パフォーマンスとスケーラビリティの観点から、効率的でパフォーマンスに優れたデータベースファイルシステムレイアウトを設計することが重要です。重要なのは、これはデータベースのサイズに依存しないということです。一般に、巨大なサイズのデータベースには高性能のディスクアーキテクチャが必要であるという認識がありますが、これは真実ではありません。データベースのサイズが50GBの場合でも、優れたディスクアーキテクチャが必要になる場合があります。そして、これは追加費用を負担せずに不可能かもしれません。
同じためのヒントは次のとおりです。
- データベースに複数のテーブルスペースがあり、トランザクションレートに基づいてテーブルとインデックスがグループ化されていることを確認します。
- バランスの取れたI/Oを実現するには、テーブルスペースを複数のディスクファイルシステムに配置する必要があります。これにより、複数のCPUが機能して、複数のディスク間でトランザクションを実行できるようになります。
- トランザクションの多いデータベースの別のディスクにpg_xlogまたはpg_walディレクトリを配置することを検討してください。
- インフラストラクチャに基づいて*_costパラメータが設定されていることを確認してください
- iostat、mpstat、およびその他のI / O監視ツールを使用して、すべてのディスクのI / O統計を理解し、それに応じてデータベースオブジェクトを設計/管理します。
PostgreSQL on Cloud
インフラストラクチャは、データベースのパフォーマンスを向上させるために重要です。パフォーマンスエンジニアリング戦略は、インフラストラクチャと環境によって異なります。クラウドでホストされているPostgreSQLデータベースには特別な注意が必要です。ローカルデータセンターの物理ベアボーンサーバーでホストされているデータベースのパフォーマンスベンチマークは、パブリッククラウドでホストされているデータベースとはまったく異なる場合があります。
一般に、クラウドインスタンスは少し遅くなる可能性があり、ベンチマークは特にI/Oの点でかなりの差があります。クラウドインスタンスを選択/構築する前に、必ずI/Oレイテンシチェックを実行してください。驚いたことに、クラウドインスタンスのパフォーマンスは、同じクラウドプロバイダーからのものであっても、地域によっても異なる可能性があることを学びました。これをさらに説明すると、2つの異なるリージョンで同じ仕様が構築されたクラウドインスタンスでは、異なるパフォーマンス結果が得られる可能性があります。
一括データロード
オフラインのバルクデータロード操作は、データベースの世界ではかなり一般的です。これらはかなりのI/O負荷を生成する可能性があり、その結果、データ負荷のパフォーマンスが低下します。私はDBAとしての経験の中でそのような課題に直面しました。多くの場合、データの読み込みは非常に遅くなり、調整する必要があります。ここにいくつかのヒントがあります。これらはオフラインのデータ読み込み操作にのみ適用され、ライブの本番データベースでのデータの読み込みとは見なされません。
- ほとんどのデータロード操作は営業時間外に実行されるため、データロード中に次のパラメーターが構成されていることを確認してください-
- チェックポイントがパフォーマンスの問題を引き起こさないように、チェックポイント関連の値を十分に大きく構成します。
- full_page_writeをオフにします
- ウォルマートのアーカイブをオフにします
- synchronous_commitパラメーターを「オフ」に構成します
- データロードの対象となるテーブルの制約とインデックスを削除します(データロード後に、より大きなwork_mem値を使用して制約とインデックスを再作成できます)
- CSVファイルからデータを読み込む場合は、maintenance_work_memを大きくすると良い結果が得られます。
- パフォーマンスには大きなメリットがありますが、データの破損につながる可能性があるため、fsyncパラメータをオフにしないでください。
クラウドパフォーマンス分析のTIPS
- pgbenchを使用して徹底的なI/Oレイテンシテストを実行します。私の経験では、TPS評価の一部としてディスク遅延チェックを実行すると、ごく普通のパフォーマンス結果が得られました。一部のパブリッククラウドインスタンスのキャッシュパフォーマンスに問題がありました。これは、データベース用に選択されたクラウドインスタンスに適切な仕様を選択するのに役立ちます。
- クラウドインスタンスは、地域ごとに異なるパフォーマンスを示す可能性があります。ある地域に特定の仕様を持つクラウドインスタンスは、別の地域に同じ仕様を持つクラウドインスタンスと比較して異なるパフォーマンス結果をもたらす可能性があります。異なるリージョンの複数のクラウドインスタンス(同じクラウドベンダーのすべて同じ仕様)で実行されたpgbenchテストでは、いくつかのインスタンスで異なる結果が得られました。これは、クラウドに移行する場合に特に重要です。
- クラウドでのクエリのパフォーマンスには、別の調整アプローチが必要になる場合があります。 DBAは、健全なクエリ実行計画が生成されるように、*_costパラメーターを使用する必要があります。
Tools to Monitor PostgreSQL Performance
There are various tools to monitor PostgreSQL performance. Let me highlight some of those.
- pg_top is a GREAT tool to monitor PostgreSQL database dynamically. I would highly recommend this tool for DBAs for various reasons. This tool has numerous advantages, let me list them out:
- pg_top tool uses textual interface and is similar to Unix “top” utility.
- Will clearly list out the processes and the hardware resources utilized. What excites me with this tool is that it will clearly tell you if a particular process is currently on DISK or CPU - in my view that’s excellent. DBAs can clearly pick the process running for longer time on the disk.
- You can check the EXPLAIN PLAN of the top SQLs dynamically or instantly
- You can also find out what Tables or Indexes are being scanned instantly
- Nagios is a popular monitoring tool for PostgreSQL which has both open-source and commercial versions. Open source version should suffice for monitoring. Custom Perl scripts can be built and plugged into Nagios module.
- Pgbadger is a popular tool which can be used to analyze PostgreSQL log files and generate performance reports. This report can be used to analyze the performance of checkpoints, disk sorting.
- Zabbix is another popular tool used for PostgreSQL monitoring.
ClusterControl is an up-and-coming management platform for PostgreSQL. Apart from monitoring, it also has functionality to deploy replication setups with load balancers, automatic failover, backup management, among others.