はじめに
Webシステムの応答時間が長くなると、TomcatのThread数やJVMのHeap容量が注目されがちです。しかし、Requestの大半がデータベースの処理完了を待っている場合、Application Server側の設定だけを変更しても改善しません。
データベースのパフォーマンス設計では、SQLの処理特性を把握し、CPU・メモリ・ストレージの処理能力と、Transaction・同時実行数を整合させることが重要です。Connectionを増やす前に、1件のSQLがどれだけのリソースを消費し、どこで待つ可能性があるかを理解する必要があります。
この記事では、Webシステムのデータベース処理に着目し、Oracle DatabaseとPostgreSQLに共通する性能設計の考え方と、両製品の実装上の違いを解説します。SQLの処理構造からCPU・メモリ・Storage I/O、Transaction、Connection Pool、性能試験、監視までを一通り整理します。
本記事の前提:Linux上のOracle DatabaseおよびPostgreSQLを使用する一般的なWebシステムを想定します。パラメータの既定値や利用可能な機能は製品・バージョン・Editionによって異なります。PostgreSQLの監視ビューもバージョンにより異なるため、使用環境の公式ドキュメントを確認してください。掲載する数値は説明用であり、一律の推奨値ではありません。
データベースのパフォーマンス設計とは
データベースの役割は、SQLを受け付け、必要なデータを読み書きし、Transactionの整合性と永続性を維持することです。性能要件としては、単位時間あたりの処理件数(TPS)、SQLや業務Transactionの応答時間、同時実行数などを定義します。
| 観点 | 設計で決めること | 主な確認指標 |
|---|---|---|
| Throughput | 通常時・ピーク時に必要な処理能力 | TPS、SQL実行数 |
| Latency | SQL・Transactionに許容する時間 | 平均、p95 / p99、待機時間 |
| CPU / Memory | SQL処理とキャッシュに割り当てる容量 | CPU時間、キャッシュ、作業用メモリ |
| Storage | データ・ログ書き込みを支える能力 | IOPS、Throughput、Latency |
| Concurrency | 同時に処理するSQLとTransactionの量 | Active Session、接続数、Lock待ち |
重要なのは、Connection数やキャッシュ容量といった個別の設定値を最大化することではありません。必要なTPSと応答時間を満たしながら、ピーク時や障害時にも処理能力の余裕を確保することが目標です。
TPSと応答時間・同時実行数の関係
TPSだけでは性能を判断できません。例えば、同じ500TPSでも、業務Transactionの平均応答時間が20msと200msでは、システム内に滞留する処理数が異なります。安定した状態ではLittle’s Law(平均同時滞留数 ≒ 到着率 × 平均滞留時間)が目安になります。ただし、DB接続数と同時滞留数は同一ではなく、待機やアプリケーション処理も区別して測定します。
データベースの処理構造
まず、ApplicationからSQLが届いてから結果が返るまでの処理を整理します。以下は共通的な概念図であり、OracleとPostgreSQLで内部のProcess構成やキャッシュ管理は異なります。

同じSELECTでも、Indexを利用して少数の行を取得する場合と、大量の行を読み込んでSortする場合では、CPU・メモリ・I/Oの消費量が大きく異なります。UPDATEやINSERTでは、データの変更に加えてREDO / WALの生成やLockも関係します。
| 処理 | 主なリソース | 性能設計のポイント |
|---|---|---|
| Parse / Plan | CPU、共有メモリ | 不要な再解析、統計情報、実行計画 |
| Scan / Join | CPU、キャッシュ、I/O | アクセスする行数、Index、Join方式 |
| Sort / Hash | CPU、作業用メモリ、一時I/O | メモリ不足によるDisk Spill |
| UPDATE / INSERT | CPU、キャッシュ、ログI/O | 更新量、Index維持、COMMIT |
| 同時実行 | CPU、メモリ、Lock | 競合と待ち行列 |
参考までに、OracleとPostgresの処理構造の違いを以下に記載します。

CPUの性能設計
データベースのCPUは、SQLの解析・実行、行の評価、Join、Sort、集約、データの圧縮などに使われます。SQLの実行回数だけでなく、1回あたりのCPU消費量がサイジングに影響します。
たとえば、1TransactionのDB側CPU時間の合計が平均10msで、毎秒500件を処理する場合、毎秒5 CPU秒が必要です。概算では5 Coreを100%使用する計算に相当します。ただし、これは待機時間を含まないCPU需要の理論値です。5 Coreを割り当てれば500TPSを安定して処理できるという意味ではなく、OS・DBのバックグラウンド処理、並列実行、ピーク変動、CPU使用率の余裕を別途考慮します。
| 観点 | Oracle | PostgreSQL |
|---|---|---|
| SQL実行 | Server Processなどが実行 | 通常は接続ごとのBackend Processが実行 |
| 並列処理 | Parallel Execution | Parallel Query |
| 主な確認対象 | DB CPU、Active Session、Wait Event | Process CPU、pg_stat_activity、pg_stat_statements |
並列度を上げると一つのSQLの処理時間が短くなる場合がありますが、同時実行される別のSQLに使えるCPUが減ることもあります。オンライン処理では、個々のSQLの短縮だけでなく、システム全体のTPSとp95 / p99を評価します。
メモリの性能設計
データベースでは、データのキャッシュとSQL実行時の一時的な作業領域にメモリを使用します。OracleとPostgreSQLはメモリの構成が異なるため、パラメータを単純に1対1で置き換えることはできません。
| 用途 | Oracle | PostgreSQL |
|---|---|---|
| 共有領域 | SGA | 共有メモリ |
| データキャッシュ | Database Buffer Cache | shared_buffersとOS Page Cache |
| SQL共有情報 | Shared Poolなど | 各Backendの管理情報や共有キャッシュなど |
| 作業用メモリ | PGA | work_memなど |
| ログバッファ | Redo Log Buffer | WAL Buffers |
Oracle:SGAとPGA
SGAはInstance内で共有するメモリ領域で、Database Buffer Cache、Shared Pool、Redo Log Bufferなどを含みます。一方、PGAはServer Processなどが使用するメモリで、SortやHash Joinなどの作業にも関係します。
SGA_TARGET、SGA_MAX_SIZE、PGA_AGGREGATE_TARGETなどは、使用するメモリ管理方式と合わせて検討します。PGAのTargetはすべての状況で使用量を厳密に制限する値ではないため、同時実行数と実測値も確認します。
PostgreSQL:共有メモリとBackendごとのメモリ
PostgreSQLでは、shared_buffersがデータページの共有キャッシュとして機能します。SortやHashなどの作業にはwork_memが関係し、メンテナンス処理にはmaintenance_work_memなどを使用します。
work_memはConnectionごとに一度だけ確保される固定容量ではありません。 一つのQueryに複数のSort / Hash処理があり、さらに複数のQueryが並列実行されれば、合計使用量が増えます。Hash処理では、通常、work_mem × hash_mem_multiplierまで使用でき、並列QueryではWorkerごとにも作業メモリを使用します。work_memに最大接続数を単純に掛けるだけでは、ピーク時のメモリ消費を正確に見積もれません。代表的なSQLの実行計画、Sort・Hashの数、並列度、同時実行数を用いて評価します。
Buffer Cacheの設計
Buffer Cacheは、頻繁に参照するデータページをメモリに保持し、ストレージからの読み込みを減らすための仕組みです。ただし、キャッシュ容量を増やすだけでは、非効率なSQLや大量の不要なデータアクセスを解決できません。
| 観点 | Oracle | PostgreSQL |
|---|---|---|
| DB側のデータキャッシュ | Database Buffer Cache | shared_buffers |
| OSとの関係 | 通常のDB File I/O方式に応じてOS Cacheの関与が異なる | 一般にOS Page Cacheも利用する |
| 設計の要点 | SGA全体の配分とWorking Set | shared_buffersとOS・他Processのメモリ配分 |
キャッシュヒット率は参考指標ですが、値が高いだけで十分とは判断できません。実際の物理読み込み量、SQL応答時間、ストレージLatency、キャッシュに収まらないWorking Setを合わせて評価します。
Storage I/Oの性能設計
データベースのI/Oは、データページの読み書き、Transaction Log、一時領域、Checkpointなどに分けて考えます。これらはI/Oサイズや同期性が異なるため、単一のIOPSだけで必要性能を決めることはできません。
| I/O | 主な処理 | 設計で確認すること |
|---|---|---|
| Data Read | Cache Miss、Scan | Read IOPS、サイズ、Latency |
| Data Write | Dirty Pageの書き出し | Write Throughput、ピーク、平準化 |
| Redo / WAL | 変更履歴の永続化 | 同期書き込みLatency、連続書き込み |
| Temporary I/O | Sort / HashのDisk Spill | 一時領域の容量とI/O性能 |
| Checkpoint | 変更済みページの書き出し | 書き込み集中時の余力 |
ストレージの性能設計では、通常時の平均値だけでなく、Batchとオンライン処理の重複、Checkpoint、Backup、障害・縮退時の負荷を考慮します。RAIDや共有ストレージを利用する場合は、通常時の実効性能に加え、ディスクやStorage Pathの障害時に残存リソースで必要なIOPS・帯域・Latencyを維持できるか確認します。
REDO / WALとCheckpointの設計
データベースは更新したデータページを毎回直ちにData Fileへ書き込むわけではありません。一般的には変更履歴を先にログへ記録し、変更済みページは後から書き出します。OracleではREDO、PostgreSQLではWALがこの役割を担います。

上図は通常の同期COMMITを単純化したものです。OracleではLGWRがREDOをオンラインREDOログに書き込み、PostgreSQLではWALの必要な範囲をFlushします。通常、COMMITのたびに変更済みデータページのData Fileへの書き出し完了を待つわけではありません。変更済みページの書き出しは後続のバックグラウンド処理やCheckpointなどで進みます。ログの永続化を緩める設定は障害時のデータ保護要件にも影響するため、性能だけで判断しません。
Checkpointによる書き込み負荷
Checkpointでは、変更済みページの書き出しや復旧に必要な情報の管理が行われます。書き込みが短時間に集中すると、通常のSQLとストレージを奪い合い、応答時間が悪化する可能性があります。
OracleではDBWRやCheckpoint関連の処理、PostgreSQLではCheckpointerやBackground Writerなどの動作を理解し、ログ生成量・書き込み量・ストレージ性能を合わせて設計します。PostgreSQLのmax_wal_sizeやcheckpoint_timeoutは、Checkpointの発生に関係する代表的な設定です。checkpoint_completion_targetはCheckpointの書き込みを時間的に分散する目標を指定します。なお、max_wal_sizeは厳密なWAL使用量の上限ではなく、レプリケーションスロットやアーカイブ処理などによってWALがさらに保持される場合があります。
| 設定 | 主な役割 | 設計上の注意 |
|---|---|---|
| max_wal_size | WAL量に基づくCheckpoint発生の目安 | 厳密な容量上限ではない |
| checkpoint_timeout | 時間に基づくCheckpoint間隔の上限 | 頻度と復旧時間のバランス |
| checkpoint_completion_target | Checkpointの書き込みを分散する目標 | I/O負荷とCheckpoint完了時間を確認 |
SQLと実行計画の設計
CPUやメモリを増強する前に、SQLが必要以上の行やページを読み込んでいないかを確認します。同じ結果を返すSQLでも、アクセス経路やJoin方式によって必要なリソースは大きく変わります。
| 設計項目 | 確認すること | 注意点 |
|---|---|---|
| Index | 検索条件、選択性、取得件数 | 更新時の維持コストも増える |
| Join | 結合順序、件数、方式 | 見積行数の誤差が計画に影響 |
| Sort / Aggregate | 処理行数、作業メモリ | Disk Spillで一時I/Oが増える |
| 統計情報 | データ分布、更新頻度 | 古い統計情報で非効率な計画になる場合がある |
| 結果件数 | 不要な列・行を取得していないか | DBだけでなくNetworkやJVMにも影響 |
OracleとPostgreSQLの実行計画
OracleではOptimizerが統計情報などを基に実行計画を選択し、PostgreSQLではPlanner / Optimizerが同様の役割を担います。どちらもIndexを使えば常に速いわけではありません。大量の行を取得する場合、Full ScanやSequential Scanの方が適することもあります。
-- PostgreSQL:実行計画と実測を確認する例
EXPLAIN (ANALYZE, BUFFERS)
SELECT * FROM orders WHERE customer_id = 100;EXPLAIN ANALYZEはSQLを実際に実行します。更新系SQLや高負荷の本番環境では副作用と実行負荷に注意してください。Oracleでは、DBMS_XPLAN.DISPLAY_CURSORなどを利用して実行計画を確認できます。実測行数や実行統計を確認するには、統計収集の設定や必要な権限を確認します。どちらの製品でも、推定行数と実測行数、実行時間、読み込んだブロック数などを比較し、想定外のFull ScanやJoin、Sortを調査します。
TransactionとLockの設計
SQL単体が高速でも、複数のTransactionが同じデータを更新するとLock待ちが発生します。長時間Transactionは、他の処理の待ち時間だけでなく、不要になった行Versionの管理やログ・復旧にも影響します。
| 観点 | 設計で確認すること |
|---|---|
| Transaction時間 | DB接続を保持したまま外部APIや利用者入力を待たないか |
| 更新順序 | 複数Transactionが同じ表・行を異なる順序で更新しないか |
| Isolation Level | 業務整合性と同時実行性の要件に合っているか |
| Lock待ち | 競合する行、待機時間、Timeoutを把握できるか |
| 長時間Transaction | OracleのUNDO、PostgreSQLのVACUUMへの影響を考慮したか |
OracleとPostgreSQLはいずれもMVCCに関連する仕組みを持ちますが、OracleはUNDO情報、PostgreSQLは行VersionとVACUUMなど、実装が異なります。特にPostgreSQLでは長時間Transactionが古い行Versionの回収を妨げる可能性があるため、定期Batchや接続Poolの運用も含めて設計します。
Connection・Sessionと同時実行数の設計
ここまでで、SQL一件あたりのリソース消費と、CPU・メモリ・I/Oの処理能力を整理しました。その結果を基に、同時にどれだけのSQLやTransactionを実行させるかを決めます。
| 観点 | Oracle | PostgreSQL |
|---|---|---|
| 接続・処理の構造 | SessionとServer Processなど。Dedicated / Shared Server構成で異なる | 通常は接続ごとにBackend Processを使用 |
| 主な上限 | PROCESSES、SESSIONSなど | max_connectionsなど |
| 設計上の注意 | Process / Session数とPGAなどのメモリ | Backend数と各Processのメモリ・CPU負荷 |
Connection数と実行中SQL数は同じではありません。 接続を保持していても待機中の場合があり、反対に少数のConnectionでも重いSQLが並列に実行されればCPUやI/Oが飽和します。接続数だけでなく、Activeな処理と待機時間を測定します。
TomcatのConnection Poolとの整合
Tomcat側のDB Connection Poolは、データベースへ同時に流す処理量を制御する重要な要素です。Poolを大きくすると接続待ちが減る場合がありますが、DB側でCPU・I/O・Lock競合が増えれば、SQLの実行時間が長くなる可能性があります。

例えばTomcatのmaxThreadsが400、DB Connection Poolの上限が100でも、常に300 Threadが待つわけではありません。DBへアクセスしないRequestや、Connectionを保持していない処理もあります。Poolが満杯になると、接続を取得しようとするRequestは待機し、Tomcatの処理Threadを占有することがあります。SQLの遅延がConnection保持時間を延ばし、接続待ちが増えてプール枯渇に至ることもあります。実際のDB利用率、Connection保持時間、待機時間、SQLの処理能力からPool容量を決めます。
複数のTomcat NodeやBatch、運用ツールが同じDBを利用する場合は、それぞれのPool上限を合算したピーク接続数と、同時実行時の負荷を考慮します。DBの上限値までPoolを割り当てず、管理接続や障害対応の余裕も残します。
Connection Poolが飽和するまでの流れ
SQLの実行遅延 → Connection保持時間の増加 → PoolのActive接続数が上限に到達 → 接続取得待ちの増加 → Requestの応答遅延・Timeoutという連鎖が起きることがあります。Pool上限を増やす前に、SQLの実行時間、Lock待ち、接続返却漏れ、DB側のCPU・I/O飽和を確認します。
主要パラメータの設計
性能パラメータは、先に必要な処理能力とメモリ配分を定義し、その結果を設定へ反映します。以下は設計対象となる代表例です。既定値や変更方法は使用するバージョンの公式マニュアルで確認してください。
| 設計観点 | Oracle | PostgreSQL |
|---|---|---|
| 共有メモリ | SGA_TARGET、SGA_MAX_SIZE | shared_buffers |
| 作業用メモリ | PGA_AGGREGATE_TARGET | work_mem、maintenance_work_mem |
| 接続数 | PROCESSES、SESSIONS | max_connections |
| 並列処理 | PARALLEL関連設定 | max_parallel_workers_per_gatherなど |
| ログ・Checkpoint | REDO Log構成、Checkpoint関連設定 | max_wal_size、checkpoint_timeout、checkpoint_completion_target |
| 統計情報 | Optimizer Statistics | ANALYZE、autovacuum関連設定 |
パラメータをまとめて変更すると、改善・悪化の原因が分からなくなります。変更前のTPS、SQL応答時間、CPU、I/O、待機時間を残し、仮説ごとに比較します。
障害・縮退時の性能設計
通常時の性能要件を満たしていても、NodeやStorage Pathの障害、Standbyへの切り替え、Replicaの停止によって残存リソースへ負荷が集中する場合があります。性能設計では、可用性だけでなく、切り替え後の処理能力も確認します。
| 事象 | 性能面の確認事項 |
|---|---|
| Primary停止・切り替え | 切り替え先のCPU・メモリ・I/O、Connection再確立 |
| Replica停止 | 参照処理の振り分け先、Primaryへの追加負荷 |
| Storage Path障害 | 残存Pathの帯域・Latency、I/O Timeout |
| 復旧後 | CacheのWarm-up、Replicationの追いつき、負荷の再分散 |
OracleのData Guard、PostgreSQLのStreaming Replicationなどは構成や同期方式によって性能特性が異なります。同期転送ではCommit Latency、非同期転送では遅延やデータ保護要件とのTrade-offを検討します。利用する製品・構成で実際に縮退試験を行います。
データベースの性能試験
性能試験では、DB単体のBenchmarkだけでなく、Tomcatからの実際のSQL構成、Transaction比率、データ量を再現します。Read中心かWrite中心か、検索条件の分布、Hot Rowへの更新集中などによって結果が変わります。
| 試験 | 主な確認内容 |
|---|---|
| 通常負荷 | 目標TPS、SQL応答時間、CPU・I/O |
| ピーク負荷 | 同時実行数、Lock、接続待ち、p95 / p99 |
| 段階的な負荷増加 | 処理能力の飽和点と待機時間の増加 |
| 長時間試験 | Cache、Checkpoint、VACUUM、ログ増加 |
| Batch重複 | オンライン処理へのCPU・I/O・Lock影響 |
| 障害・縮退 | Failover後のTPS、応答時間、復旧時間 |
合格条件は、例えば「通常時の目標TPSを達成し、業務Transactionのp95 / p99が要件以内、Error率が許容範囲内」といったサービス要件から定義します。DBのCPU使用率やキャッシュヒット率だけを合否基準にしません。負荷生成側が先に限界へ達していないことも確認します。
性能設計を確認する
設計値が妥当かどうかは、DB内部の統計情報とOSの観測値を合わせて確認します。
| 観点 | Oracle | PostgreSQL |
|---|---|---|
| 接続・実行中SQL | V$SESSION、V$PROCESS | pg_stat_activity |
| SQL負荷 | V$SQL、実行計画 | pg_stat_statements、EXPLAIN |
| 待機・競合 | Wait Event、ASH / AWR(利用条件に注意) | wait_event、pg_locksなど |
| I/O | DB統計とOSのiostatなど | pg_stat_io(対応バージョン)、OSのiostatなど |
| ログ・Checkpoint | REDO生成量、書き込み待機 | WAL統計、Checkpoint統計 |
PostgreSQL:SQL負荷と実行中の処理
-- 現在の接続状態と待機状況
SELECT state, wait_event_type, wait_event, count(*)
FROM pg_stat_activity
GROUP BY state, wait_event_type, wait_event
ORDER BY count(*) DESC;
-- pg_stat_statementsが有効な環境で負荷の大きいSQLを確認
SELECT calls, total_exec_time, mean_exec_time, query
FROM pg_stat_statements
ORDER BY total_exec_time DESC
LIMIT 10;pg_stat_statementsは拡張機能の導入と必要な設定が前提です。統計値は累積期間やリセット時刻を確認し、短い計測区間の負荷を評価する場合は差分を使います。SQL本文には業務情報が含まれる場合があるため、取得・保管権限を管理します。
Oracle:SessionとWait Event
-- 実行中Sessionの状態を確認する例
SELECT sid, serial#, status, event, wait_class, sql_id
FROM v$session
WHERE type = 'USER'
AND status = 'ACTIVE';STATUS = 'ACTIVE'はCPU実行中だけを意味しません。Active SessionがすべてCPUで実行中とは限りません。I/OやLockなどを待っている場合もあるため、Wait EventとSQLを関連付けて確認します。AWR / ASHなどの利用にはEditionやライセンス条件が関係する場合があるため、利用環境の契約を確認してください。
Oracle RAC:Instance別にActive Sessionを確認する
Oracle RAC環境では、単一InstanceのV$SESSIONだけでなく、GV$SESSIONを使うとInstance別のActive Sessionを確認できます。ActiveにはCPU実行中と待機中の両方が含まれます。
SELECT inst_id, status, wait_class, event, COUNT(*) AS session_count
FROM gv$session
WHERE type = 'USER' AND status = 'ACTIVE'
GROUP BY inst_id, status, wait_class, event
ORDER BY inst_id, session_count DESC;まとめ
データベースの性能設計では、まずSQLの処理構造を理解し、CPU・メモリ・Storage I/Oの必要量を見積もります。そのうえでTransactionとLock、Connection数を設計し、Tomcatから流入する負荷との整合を取ります。
| 設計項目 | 確認すること |
|---|---|
| CPU | SQL一件あたりのCPU消費量とピークTPS |
| Memory | Buffer Cache、作業用メモリ、同時実行時の使用量 |
| Storage | Data / REDO・WAL / Temporary I/Oの特性 |
| SQL | 実行計画、Index、統計情報、不要なデータアクセス |
| Transaction | Lock競合、長時間Transaction、COMMIT |
| Connection | TomcatのPoolとDB側の処理能力 |
| 障害時 | 切り替え先の処理能力と復旧時の負荷 |
Connectionを増やす前に、SQL一件のコストを把握する。メモリを増やす前に、何がキャッシュされ、何がDiskへ書き出されるかを理解する。通常時だけでなく、ピークと縮退時の処理能力を検証する。 これがOracleとPostgreSQLに共通する性能設計の基本です。
設計した処理能力を超えるRequestが流入する場合は、Connection Poolの上限やTimeoutを適切に設定し、必要に応じてRate LimitやBackpressureによってDBへの負荷を制御します。Retryを導入する際は、障害時に再試行が集中してDBの負荷を増幅させないよう、再試行回数や間隔も設計します。


コメント