MongoDB vs PostgreSQL: 2026年に適したデータベースの選び方
MongoDBとPostgreSQLを、データモデル、クエリ、トランザクション、スケーリング、セキュリティ、運用、コスト、実際のアプリケーション適合性から比較します。

この比較の考え方
関係性、制約、トランザクション、柔軟なレポートがワークロードの中心ならPostgreSQLを選びます。ほとんどの操作が、フィールド構成に大きなばらつきのある、範囲が限定された自己完結型ドキュメントの読み取りや更新ならMongoDBを選びます。どちらが常に高速、あるいは常に簡単ということはありません。
機能一覧ではなく、アプリケーションから考え始めましょう。請求システムとコンテンツカタログでは、どちらもAPIでJSONを返すとしても、失敗時に問題になる条件が違います。データベースは、アプリケーションで最も難しい操作を、単に実現可能にするだけでなく、当たり前に扱えるようにすべきです。
両方の選択肢を、次の5つの具体的な問いで評価してください。
- 1つのトランザクションで必ず一緒に変更しなければならないレコードはどれか。
- エンティティの境界をまたぐクエリは何か。また、どのくらい頻繁に変わるか。
- アプリケーションコードが失敗しても守らなければならないルールは何か。
- 1つの論理レコードはどこまで大きくなりうるか。子コレクションは上限なく増えうるか。
- データベースの運用、復元、チューニング、障害対応は誰が担うのか。
SaaSのアカウント、権限、注文、請求、在庫、監査証跡、CRM、ERPには、通常PostgreSQLのほうが低リスクな標準選択です。これらの領域には多対多の関係と、テーブル、外部キー、一意制約、SQLに適した不変条件が数多くあります。
MongoDBは、コンテンツ項目、テナントごとに属性が異なる商品レコード、設定ドキュメント、イベントペイロードなど、通常は1つのオブジェクトとして取得する集約に向いています。柔軟なドキュメント構造により初期実装を短縮できますが、チームはスキーマの進化を管理し続ける必要があります。
それぞれが明確に分離された領域を所有するなら、両方のデータベースを使うのは妥当です。境界が曖昧な場合は高くつきます。ストアが2つあれば、バックアップシステム、監視モデル、セキュリティ設定、同期の仕組みも2つ必要です。片方のデータベースだけでは、継続的なモデリングまたはスケーリングの問題が生じる場合にだけ、そのコストを引き受けましょう。
データモデル: ドキュメントかリレーショナルテーブルか
MongoDBは範囲が限定された集約として保存できるデータに向き、PostgreSQLは独立して変化するエンティティ間の関係によって価値が決まるデータに向きます。この違いはJSONと行の違いより深く、整合性ルールをどこに置くかを決めます。
MongoDBの注文では、配送先住所と明細を埋め込めます。
{
"_id": "order_1042",
"customerId": "customer_28",
"status": "paid",
"shippingAddress": {
"city": "Austin",
"country": "US"
},
"items": [
{ "productId": "product_7", "quantity": 2, "unitPrice": 19.95 }
]
}
インデックスを使った1回の検索で、注文全体を返せます。1回の更新で、注文と埋め込み済みの明細を原子的に変更することもできます。これらの要素が同じライフサイクルを共有し、配列のサイズに上限がある場合には魅力的です。
同等のPostgreSQLモデルでは、独立した意味を持つ事実を分けます。
CREATE TABLE orders (
id bigint PRIMARY KEY,
customer_id bigint NOT NULL REFERENCES customers(id),
status text NOT NULL,
placed_at timestamptz NOT NULL
);
CREATE TABLE order_items (
order_id bigint NOT NULL REFERENCES orders(id),
product_id bigint NOT NULL REFERENCES products(id),
quantity integer NOT NULL CHECK (quantity > 0),
unit_price numeric(12, 2) NOT NULL CHECK (unit_price >= 0),
PRIMARY KEY (order_id, product_id)
);
このモデルでは、注文をまたぐレポートや商品との関係を直接扱えます。注文または商品が存在しない明細は、データベースが拒否できます。また、購入時に記録した価格を保ったまま、商品を独立して変更できます。
アカウントが生成したすべてのイベントのように、上限なく増えるコレクションには埋め込みは不向きです。1つの成長し続けるドキュメントは書き込みの集中点になり、帯域幅を多く消費し、やがてMongoDBの16 MiBのドキュメント制限に達します。代わりに、イベントは別々のドキュメントとして保存してください。
正規化しすぎることも問題です。小さな値オブジェクトを複数テーブルに分けると、有用な独立性を生まないまま結合だけが増えます。完了した注文で記録する配送先住所は、多くの場合、顧客の現在の住所への生きた参照ではなく、履歴のスナップショットです。
長く使えるモデリングの原則は、共に変化し、サイズが限定されるデータは埋め込むことです。独立して変化するデータ、多くの関係に関わるデータ、予測できる上限なく増えるデータは参照するか正規化します。
スキーマの進化とデータ整合性
MongoDBはフィールドを追加しやすく、PostgreSQLは均一な形を強制しやすいデータベースです。本番環境での安全性は、どちらでも規律あるマイグレーションにかかっています。
MongoDBのコレクションには、フィールドや型が異なるドキュメントを入れられます。この柔軟性は、テナントやコンテンツタイプで属性が異なる場合に役立ちますが、同じ概念の互換性がないバージョンをいくつも生むこともあります。フィールド名を変更すると古いドキュメントが残り、すべての読み取り側にフォールバック処理が必要になります。
MongoDBはJSON Schema風のルールによるコレクション検証をサポートしています。チームは段階的に検証を導入し、既存ドキュメントをバックフィルしてから、選んだ形に違反する新規書き込みを拒否できます。スキーマバージョン用フィールドを使えば、ワーカーが古いドキュメントを予測可能な形で移行する助けになります。ただし、検証の代わりにはなりません。
PostgreSQLの変更は明示的です。通常はNULLを許可する列を追加し、必要に応じて古い形式と新しい形式の両方に書き込むコードをデプロイし、制御されたバッチでバックフィルし、データを検証してから、より厳しい制約を追加します。大きなインデックスは、書き込みへの影響を抑えるため並行して構築できます。外部キーと一部の制約も、完全な検証の前に段階的に導入できます。
エンジンが表現できる有用な不変条件は、データベースに置きます。
- 識別子、冪等性トークン、所有者ごとに1件だけ存在するレコードには一意制約を使う。
- 欠損データを決して参照してはならない関係には外部キーを使う。
- 数量が正であることなど、局所的なルールには
CHECK制約を使う。 - リモートサービスや頻繁に変わるポリシーが必要な文脈依存のルールにはアプリケーション検証を使う。
- サポートするすべてのスキーマバージョンからの移行経路はテストで確認する。
わかりやすいエラーメッセージや業務フローのために、アプリケーション検証は引き続き必要です。データベース制約は、競合、見落としたコードパス、管理用スクリプト、同じデータに書き込む将来のサービスに対する最後の防壁になります。
柔軟なスキーマとは、管理された変化を意味し、未知の変化を意味しません。素早い反復のためにMongoDBを選ぶ前に、ドキュメントの形を誰が管理するのか、互換性のない変更をどう検出するのか、古いドキュメントをいつ書き換えるのかを決めてください。
クエリ、結合、レポート
変化する複数エンティティ横断の問いにはPostgreSQLのほうが直接的で、クエリが1つのドキュメント境界に沿う場合はMongoDBが簡潔です。プロダクトにレポート要件が積み重なるほど、クエリの扱いやすさは重要になります。
SQLは宣言型です。フィルター、結合、グループ化、共通テーブル式、ウィンドウ関数、サブクエリ、集合演算を、保存モデルを変えずに組み合わせられます。PostgreSQLのプランナーは、統計情報と利用可能なインデックスから、結合アルゴリズムとアクセスパスを選びます。
正規化した注文データをまたぐ売上クエリも読みやすく保てます。
SELECT
o.customer_id,
SUM(oi.quantity * oi.unit_price) AS revenue
FROM orders AS o
JOIN order_items AS oi ON oi.order_id = o.id
WHERE o.status = 'paid'
AND o.placed_at >= CURRENT_DATE - INTERVAL '30 days'
GROUP BY o.customer_id
ORDER BY revenue DESC;
MongoDBでは、単純な取得には直接のfind操作を使い、変換には集約パイプラインを使います。明細を埋め込む場合、同等の計算では順序づけられたステージでドキュメントを処理します。
db.orders.aggregate([
{ $match: { status: "paid", placedAt: { $gte: startDate } } },
{ $unwind: "$items" },
{
$group: {
_id: "$customerId",
revenue: { $sum: { $multiply: ["$items.quantity", "$items.unitPrice"] } }
}
},
{ $sort: { revenue: -1 } }
])
パイプラインは強力ですが、ステージの順序が意味とリソース使用量に影響します。大きな配列では、$unwind の後に処理対象が大きく増えることがあります。早い段階でフィルターと投影を行えば、そのコストを減らせます。
MongoDBの $lookup は、別コレクションのドキュメントを結合します。特定の関係には便利で、とくに結合先にインデックスがあり、結果が小さいままなら有効です。よく使うリクエストで複数の $lookup ステージが必要なモデルは、境界がリレーショナルであることを示しているかもしれません。
PostgreSQLは、ほとんどのレポートツールがSQLを話すため、一般にビジネスインテリジェンス、財務レポート、コホート分析、予定外の問いに向いています。MongoDBのレポートは、ディメンションがすでに共存している場合や、用意された読み取りモデルがレポートに合う場合にうまく機能します。アドホック分析が多いチームは、主データベースに関係なく運用データをデータウェアハウスへエクスポートすることがよくあります。
オブジェクトマッピングによって、このトレードオフがなくなるわけではありません。ORMでPostgreSQLの行をオブジェクトのように扱え、オブジェクトドキュメントマッパーでMongoDBのドキュメントにクラスを与えられます。それでも、負荷時の挙動を決めるのは、保存された関係、インデックス、整合性ルールです。
トランザクションと同時実行性
複数行、複数テーブルのトランザクションにはPostgreSQLが最も自然なモデルを提供します。一方MongoDBは、単一ドキュメントの変更に最も低コストな原子性の境界を提供し、必要に応じてより広いトランザクションもサポートします。正しい選択は、同時リクエストの中でも守るべき不変条件によって決まります。
PostgreSQLはマルチバージョン同時実行制御を使います。通常の読み取りと書き込みは並行して進められますが、行ロック、明示的ロック、長時間トランザクション、スキーマ変更によって待機が発生することはあります。デフォルトの分離レベルはRead Committedです。Repeatable Readでは安定したトランザクションスナップショットが得られ、Serializableは安全に順序付けできない実行を検出します。
MongoDBで1つのドキュメントを変更する操作は原子的です。そのため、上限のある集約を埋め込むと調整を減らせます。MongoDBはレプリカセットとシャードクラスタでACIDの複数ドキュメントトランザクションもサポートしています。こうしたトランザクションは調整を増やし、実行中はリソースを保持し、アプリケーションがトランザクション全体を再試行する必要がある一時的な失敗を生むことがあります。
MongoDBでは、read concern、write concern、read preferenceを別々に設定できます。これらは、読み取りでどのデータを観測できるか、書き込みを何台のレプリカセットメンバーが確認する必要があるか、読み取りをセカンダリに送れるかに影響します。レイテンシ制御として扱う前に、正しさに関わる設定として扱ってください。
どちらのデータベースも、外部の決済プロバイダーをローカルデータベーストランザクションに含めることはできません。ネットワークリクエスト中にトランザクションを開いたままにすると競合が増え、それでも両方のシステムを原子的にコミットさせることはできません。より安全な決済フローでは、保留中の注文とアウトボックスイベントを1つのデータベーストランザクションで記録し、外部リクエストを冪等に処理してから、結果を記録します。
同時実行のテストでは、成功したリクエストだけでなく、業務上の競合を対象にしてください。たとえば、最後の1個を予約する2人の購入者、同じジョブを取得する2つのワーカー、同じ一意名を割り当てる2人の管理者です。PostgreSQLでは、制約、行ロック、原子的な文でこうした操作を表現できることが多くあります。MongoDBでは、条件付き更新、一意インデックス、トランザクションを使えます。
厳密なルールが独立して保存された多くのレコードにまたがるなら、通常PostgreSQLのほうがアプリケーション側の調整が少なく済みます。各ルールが適切に設計された1つのドキュメントに収まるなら、MongoDBの原子的なドキュメント操作はシンプルで効果的です。
中間の選択肢としてのPostgreSQL JSONB
PostgreSQL JSONBは、安定したリレーショナルフィールドの周囲に、限られた進化中の属性がある場合に有力な選択肢です。ドキュメント型の問題をすべてリレーショナルな問題に変えるわけではありませんが、2つ目のデータベースを不要にできることがあります。
一般的な設計では、ID、所有者、状態、タイムスタンプを型付き列に保存し、任意属性を jsonb に置きます。外部キーが関係を保護し、通常のインデックスが頻繁なフィルターを支え、GINまたは式インデックスが選んだJSON述語を高速化します。
CREATE TABLE products (
id bigint PRIMARY KEY,
account_id bigint NOT NULL REFERENCES accounts(id),
sku text NOT NULL,
status text NOT NULL,
attributes jsonb NOT NULL DEFAULT '{}'::jsonb,
UNIQUE (account_id, sku)
);
CREATE INDEX products_attributes_gin
ON products USING gin (attributes);
これは、商品タイプごとに異なる素材、寸法、地域メタデータなどのカタログ属性に使えます。重要なフィールドがすべてJSONに埋もれ、すべてのクエリでキャスト、パス式、独自の検証が必要になる場合には向きません。
JSONBは解析済みのバイナリ表現を保存し、包含演算子をサポートし、オブジェクトプロパティの順序など重要でない書式を捨てます。また、重複するオブジェクトプロパティについては1つの値だけを保持します。元のJSONテキストを完全に再現する必要があるアプリケーションでは、そのテキストを別途保持してください。
小さなプロパティを更新しても、新しいPostgreSQLの行バージョンが作られ、大きなJSONB値が書き直されることがあります。そのため、大きく頻繁に更新されるドキュメントでは、かなりの先行書き込みログ量と不要行が生じることがあります。更新頻度の高いフィールドを列または子テーブルに分けたほうが、良い性能になることが多いでしょう。
任意のJSON内に隠れた関係を、外部キーで直接強制することはできません。頻繁にクエリ、結合、ソート、制約の対象になる値は列に昇格させます。段階的な移行には生成列や式インデックスが役立ちますが、意味が安定したら通常はリレーショナルフィールドのほうが明確です。
インデックスとクエリプラン
どちらのデータベースも、実際のフィルター、ソート、カーディナリティに合ったインデックスに依存します。無差別なインデックス追加は書き込みを遅くし、メモリを消費します。エンジンごとにインデックスの手段は異なりますが、保存モデルに逆らうアクセスパターンを救えるものはありません。
PostgreSQLは、等価、範囲、順序付き取得にB-treeインデックスを使います。GINインデックスはJSONBの包含、配列、全文検索をサポートします。GiSTとSP-GiSTは、さまざまなジオメトリ、範囲、特殊な演算子クラスをカバーします。BRINインデックスは、時間のような値と物理的な並び順が相関する非常に大きなテーブルで、コンパクトな選択肢になります。
PostgreSQLは部分インデックスと式インデックスもサポートします。有効なサブスクリプションだけの部分インデックスは、何年分もの無効レコードを含むインデックスよりずっと小さくできます。式インデックスは正規化したメールアドレスや、選んだJSONプロパティを支えられます。
MongoDBはネストしたプロパティと配列に直接インデックスを作れます。マルチキーインデックスは配列の値をインデックスエントリに展開するため、要素の所属を問うクエリを効率化できますが、インデックスが急速に大きくなることがあります。複合マルチキーインデックスでは、同じドキュメント内の配列値フィールドを2つ以上インデックス化することはできません。MongoDBは、そのほかにも地理空間、ハッシュ、ワイルドカード、部分、スパース、TTLの各インデックスを、それぞれのアクセスパターン向けに提供しています。
複合インデックスの列順は、普遍的な「最も選択性の高い順」というルールではなく、クエリ構造に従います。PostgreSQLの複数列B-treeでは、先頭列への等価条件と次の列への範囲条件が、効率のよいスキャンを生むことが多いです。MongoDBでは、一般に等価フィールド、ソートフィールド、範囲フィールドの順から始め、実際の分布では別の順序のほうが少ないエントリで済むかを確認します。
推測ではなくクエリプランを使ってください。
- PostgreSQLでは、代表的な読み取りに
EXPLAIN (ANALYZE, BUFFERS)を実行し、行数見積もり、ループ、ソート、ディスクへの退避、バッファ活動を確認します。 ANALYZEは文を実行するため、書き込みや本番トラフィックでは注意が必要です。- MongoDBでは実行統計を取得し、調べたドキュメント数、インデックスエントリ数、返した結果数を比較します。
- よく使うパラメータ値だけでなく、大きな割合のデータに該当する偏った値もテストします。
- 定期処理、管理処理、フェイルオーバー時のワークロードで使われていないことを確認してから、未使用インデックスを削除します。
あるエンドポイントには完璧なインデックスでも、別のインデックスと重複したり、すべての書き込みを増やしたりすることがあります。各インデックスを個別に承認するのではなく、インデックス全体をポートフォリオとして見直してください。
検索、地理空間、時系列のワークロード
どちらのデータベースも基本的な検索、位置情報、時系列クエリを扱えますが、要件次第では専用ツールやマネージド機能を採用する価値があります。決定は、関連性の品質、取り込み速度、保持期間、運用責任に基づいて行うべきです。
PostgreSQLの全文検索は、トークン化、辞書、重み付きドキュメントベクトル、クエリ演算子、ランキング、GINによる高速化を提供します。コーパスと関連性ルールを管理できる範囲なら、アプリケーション内の検索に適しています。トライグラムインデックスは、名前や識別子の類似検索、部分文字列検索を支えられます。
MongoDBのテキストインデックスは基本的な単語検索を扱います。MongoDBのマネージドプラットフォームは、より高度な関連性や検索ワークロード向けに設計された、個別の検索機能とベクトル検索機能も提供します。可搬性、料金、バックアップの挙動、ローカル開発を比較する際は、これらをデプロイメント固有のサービスとして扱ってください。
ベクトル検索はクエリの種類を変えるものであり、トランザクションの正本が必要なくなるわけではありません。PostgreSQLでは拡張機能でベクトルインデックスを追加でき、MongoDBのデプロイメントでは運用ドキュメントを対応するベクトル検索サービスと組み合わせられます。アプリケーション自身の埋め込みベクトルで、再現率、フィルタリング、インデックス構築時間、更新の反映、コストを評価してください。
地理空間処理では、PostgreSQLは高度なジオメトリ、座標系、空間分析のためにPostGIS拡張をよく使います。MongoDBは、位置情報を扱うアプリケーションのクエリに合う地理空間インデックスと演算子を提供します。近くの地点を探すことと、ポリゴンの修復や複雑な空間結合では必要な能力が大きく違うため、実際に必要な操作を列挙してからシンプルなほうを選んでください。
MongoDBの時系列コレクションは、測定値を内部バケットに整理し、時間ベースの期限切れをサポートします。PostgreSQLはパーティショニング、BRINインデックス、任意の拡張機能で時系列データを扱えます。長期保持と広いスキャンがトランザクション更新より重要な場合、非常に大量のテレメトリーは取り込み後に専用の分析ストアへ置くべきことがあります。
性能と代表的なベンチマーク
データレイアウト、インデックスのカバー範囲、ワーキングセットのサイズ、耐久性設定は、一般的なMongoDB対PostgreSQLのベンチマーク結果より重要なことが多いです。信頼できるテストでは、アプリケーションのデータ分布と同時実行性を再現します。
MongoDBは、1つのリクエストが1つのインデックス付きドキュメントに対応する場合、低レイテンシの読み取りを実現できます。ドキュメントが大きい場合、レスポンスで必要なのが散在する少数のフィールドだけの場合、関係に繰り返しの検索が必要な場合、その利点は小さくなります。埋め込み配列はインデックスエントリ数を増やし、更新コストを徐々に上げることもあります。
PostgreSQLは、統計情報が正確で結合列にインデックスがある場合、複雑な結合を効率よく実行できます。クエリが大きな中間結果を作る、ソートやハッシュがディスクに退避する、多数の無関係なページを繰り返し取得する場合には性能が落ちます。必要な列だけを選び、データモデルの誤りを正すことは、SQL構文を書き換えるより重要なことが多いです。
両方のシステムで、セカンダリインデックスはすべて書き込み作業を増やします。大きなJSONB値、幅の広い行、過大なドキュメント、重複した非正規化データはI/Oを増加させます。個々のクエリが速くても、接続の集中はリソースを使い尽くすことがあるため、上限のあるプールを使い、フェイルオーバー中の再接続の挙動をテストしてください。
有用なベンチマークでは、次の条件を維持します。
- 想定するワーキングセットと利用可能メモリの比率を表せる十分なデータを読み込む。
- 本番環境の整合性、ジャーナリング、レプリケーション、確認応答の設定に合わせる。
- 実際の読み取りと書き込みの比率で、主要なアプリケーション操作を再現する。
- 偏り、多忙なテナント、大規模アカウント、欠損レコード、最悪条件のフィルターを含める。
- 安定負荷時と復旧イベント時のスループットに加え、p50、p95、p99レイテンシを記録する。
一度に変える条件は1つにしてください。正規化テーブルとJSONB、埋め込みドキュメントと参照、異なるインデックスを、ハードウェアとリクエストの意味を一定に保って比べます。ウォームキャッシュでのマイクロベンチマークでは、バックアップの負荷、レプリケーション遅延、チェックポイントの挙動、プライマリ障害後の性能を予測できません。
キャパシティ計画には、データとインデックスの両方の増加を含めます。ローンチ時にメモリへ収まるインデックスが、1年後にはレイテンシの主因になることがあります。空のデータベースから外挿するのではなく、予測データ量でテストを繰り返してください。
水平スケーリングとデータ分散
MongoDBは書き込みを分散する統合シャーディングを提供します。一方PostgreSQLでは、通常は垂直スケーリング、パーティショニング、レプリカを組み合わせた後で、分散アーキテクチャを採用します。水平スケールでは、すべてのクエリに影響するルーティングと所有権の判断が必要です。
MongoDBのシャードクラスタは、シャードキーに従ってドキュメントを分散します。良いシャードキーには十分なカーディナリティがあり、単調な書き込み集中を避け、よく使うルーティング条件を支え、ストレージを均等に配分します。シャードキーを含まないクエリは、すべてのシャードにアクセスすることがあり、レイテンシとリソース使用量を増やします。
ハッシュシャーディングは連番の識別子をより均等に分散できますが、範囲の局所性は弱くなります。範囲ベースのシャーディングは対象を絞った区間を支えますが、範囲の終端がホットになりえます。ゾーンを使えば、テナントまたは地理的ルールのために、選んだ範囲を指定のシャードに置けます。リシャーディングで不適切な選択を修正できますが、大きな稼働中データセットを移すには計画と余剰容量が必要です。
MongoDBのトランザクションはシャードをまたげますが、クロスシャードの調整は、1つのシャードにルーティングされる操作よりコストが高くなります。シャードキーとよく使うクエリの両方にテナント識別子を含めるアプリケーションでは、関連する処理をローカルに保てることが多いです。
PostgreSQLのネイティブパーティショニングは、論理テーブルを子テーブルに分割します。通常は時間、テナント、別のルーティング値で分割します。パーティションプルーニングはスキャンを減らし、パーティションは保持期間に関わる操作を簡単にします。ネイティブパーティショニングだけでは書き込みを複数マシンに分散しないため、シャーディングと呼ぶべきではありません。
PostgreSQLの読み取りレプリカは、適切な読み取りトラフィックをプライマリから移せます。レプリカはプライマリの書き込み能力を増やさず、非同期レプリカは古いデータを返すことがあります。どの読み取りならその遅れを許容できるか、アプリケーションで決める必要があります。
PostgreSQLの1台の書き込みサーバーでは足りなくなったとき、チームはアプリケーションコードでシャーディングする、分散PostgreSQLの拡張やサービスを採用する、領域を独立して所有するデータベースに分ける、といった方法を選べます。どの選択肢でも、シャードをまたぐ結合、一意性、シーケンス、トランザクションの挙動が変わります。アプリケーションがグローバルな操作に依存する前に、制約をテストしてください。
スケーリング要件は数値で示すべきです。想定する毎秒書き込み数、データセットサイズ、多忙なテナントの集中度、リージョン配置、復旧目標は、単に水平スケールが必要という要件より役に立ちます。
レプリケーション、フェイルオーバー、復旧
どちらのデータベースも高可用性を提供できますが、復旧の挙動はトポロジー、確認応答ポリシー、自動化、繰り返しのテストに依存します。レプリケーションだけでは、短い停止時間もデータ損失ゼロも保証されません。
MongoDBは一般に、1つのプライマリと複数のセカンダリを持つレプリカセットで動作します。現在のプライマリが利用できなくなると、メンバーは新しいプライマリを選出します。アプリケーションは対応ドライバーを使い、サーバー選択と操作のタイムアウトを設定し、一時的なエラーを処理する必要があります。再試行可能な書き込みは一部の操作に役立ちますが、再試行でもアプリケーションの冪等性を守る必要があります。
write concernは書き込みを確認するメンバー数を制御します。read preferenceは対象となる読み取りがプライマリとセカンダリのどちらを使うかを決め、read concernは可視性の保証を制御します。低レイテンシの設定では、障害や古いデータに関するリスクが増える場合があるため、ワークロードごとに選んだ組み合わせを文書化してください。
PostgreSQLの物理ストリーミングレプリケーションは、プライマリからスタンバイへ先行書き込みログのレコードを送ります。非同期レプリケーションは可用性とレイテンシを守りますが、スタンバイが受信する前にプライマリが失われると、直近で確認済みのトランザクションを失うことがあります。同期レプリケーションはこのリスクを減らせますが、コミットレイテンシとスタンバイの健全性への影響が増します。
PostgreSQLのフェイルオーバーは、通常マネージドサービスまたは外部自動化によって調整されます。手順では適切なスタンバイを昇格させ、クライアントを切り替え、古いプライマリが競合する書き込みを受け付けないようにしなければなりません。接続プールとDNSキャッシュにより、昇格後の見かけ上の停止時間が延びることがあります。
バックアップは、誤削除や論理的な破損を含め、レプリケーションが忠実に複製してしまう障害から守ります。PostgreSQLではベースバックアップとアーカイブ済みの先行書き込みログにより、特定時点への復旧が可能です。MongoDBのデプロイメントでは、適切なツールまたはマネージドサービスを通じ、調整済みスナップショットとoplogベースの復旧を利用できます。
目標復旧時点と目標復旧時間は別々に定義してください。その後、隔離環境への完全復元をテストし、アプリケーションデータを検証し、復元した認証情報をローテーションして、経過時間を記録します。スナップショットに成功しただけでは、目標時間内に完全なサービスを復旧できる証拠にはなりません。
運用保守
PostgreSQLとMongoDBでは定期保守の内容が異なるため、小さな機能差よりチームの経験が重要になることがあります。マネージドサービスは一部の作業を減らしますが、クエリ設計、容量判断、復旧の検証までは担いません。
PostgreSQLでは、トランザクションによるデータの更新や削除で古い行バージョンが生まれます。Autovacuumは再利用可能な領域を回収し、可視性情報を更新し、トランザクションIDの枯渇を防ぎます。長時間トランザクションはクリーンアップを遅らせることがあります。不要行、テーブルとインデックスの増加、vacuumの進行状況、トランザクションの経過時間、古いスナップショットを保持しているクエリを監視してください。
プランナー統計にも注意が必要です。偏った値や相関する列により、行数見積もりが不正確になり、悪いプランが選ばれることがあります。統計対象を増やす、拡張統計を作るといった方法が、特定のクエリに役立つことがあります。クエリ性能はコード変更時だけでなく、大きなデータ増加後にも見直してください。
MongoDBのWiredTigerストレージエンジンは、キャッシュと圧縮に大きく依存します。キャッシュの逼迫、ディスクレイテンシ、ドキュメントの増加、チェックポイントの挙動、レプリケーション遅延、調べたドキュメント数と返却数の比率を監視してください。シャード環境では、バランシングの活動、不均衡なチャンク分布、シャード全体に散らばる操作にも注意します。
日常的な運用手順書は、次の5領域を扱うべきです。
- 遅いクエリの収集、担当、改善のしきい値。
- 現在の空き容量だけでなく、増加率に基づく容量アラート。
- 記録された復旧時間と検証手順を含む復元訓練。
- 認証情報のローテーションと緊急アクセス手順。
- ドライバー、拡張機能、インデックス、ロールバック計画を対象にテストしたバージョンアップ。
PostgreSQLのメジャーアップグレードでは、一般に pg_upgrade、論理レプリケーション、またはマネージド移行プロセスを使います。拡張機能の互換性によって、実現可能な経路が決まることがあります。MongoDBのアップグレードでは、対応するバージョン順序とFeature Compatibility Versionの制御を使います。シャードクラスタでは、コンポーネントの慎重な順序付けが必要です。
pg_dump や mongodump のような論理エクスポートツールは、小規模データセットや選択的な復旧に便利です。大規模環境で厳しい復旧目標を満たすには遅すぎることがあります。主な災害復旧手段として採用する前に、本番規模のデータでエクスポートとインポートの時間を測定してください。
セキュリティとガバナンス
アクセス、暗号化、監査、ネットワーク制御を明示的に設計すれば、どちらのデータベースも厳しいセキュリティ要件を満たせます。デフォルトの認証情報やプライベートネットワークだけで、監査可能なシステムになるわけではありません。
PostgreSQLのロールには、データベース、スキーマ、テーブル、シーケンス、関数、列のレベルで権限を与えられます。ビューで選んだフィールドを公開でき、行レベルセキュリティではユーザーやテナントのコンテキストに応じて行を制限できます。侵害されたサービスが自分の制限を変更できないよう、オブジェクト所有権は通常のアプリケーションロールと分けてください。
MongoDBのロールは、データベース、コレクション、クラスタリソースに対する操作権限を与えます。アプリケーション読み取り、アプリケーション書き込み、マイグレーション、監視、バックアップ、管理には別々のIDを使います。広い権限を持つ1つの認証情報を、複数サービスで共有しないでください。
実践的なコントロールの組み合わせには、次のものがあります。
- クライアントとレプリケーションの通信にTLSを必須とし、すべてのドライバーで証明書処理を確認する。
- シークレットを管理されたシークレットシステムに保存し、アプリケーション全体のリリースなしでローテーションする。
- ネットワーク経路を制限し、データベースのリスナーをパブリックインターネットへ直接公開しない。
- ポリシーで必要とされる認証、権限、スキーマ、機密データへのアクセスイベントを記録する。
- 分析担当者、サポート担当者、自動化アカウントが割り当てられた職務を超えられないことをテストする。
保存時暗号化では、データベースの機能、暗号化ストレージ、クラウド管理キーを組み合わせることがあります。MongoDBは対応するデプロイメントで、クライアント側フィールドレベル暗号化もサポートします。PostgreSQLアプリケーションでは、データベース管理者に平文を見せたくない場合、選んだ値を保存前に暗号化することが一般的です。暗号化はインデックスとクエリの選択肢を変えるため、まず保護する操作を試作してください。
ガバナンスには、データ分類、保持、削除、所在地、インシデント対応の手順も必要です。リージョン配置は所在地の目標に役立ちますが、コンプライアンスはバックアップ、ログ、サポートアクセス、委託先、データを受け取るすべてのシステムに依存します。
コスト、ライセンス、総所有コスト
より安価なデータベースとは、許容できるインフラ、サービス料金、エンジニアリング工数でワークロードを満たせるものです。ライセンス価格だけで総所有コストが決まることはほとんどありません。
複雑なクエリ、圧縮処理、インデックス保守、バックグラウンドジョブ、レプリケーションによりコンピューティングコストは上がります。ストレージには、インデックス、保持ログ、バックアップ、一時領域、非正規化による重複データが含まれます。スナップショットとリージョン間転送を数える前でも、データを持つレプリカが3台あればデータは複数コピーされます。
PostgreSQLは寛容なPostgreSQL Licenseを使っており、セルフホストとマネージドの多くのディストリビューションで利用できます。商用サポートとクラウドサービスは任意の購入です。拡張機能には独自のライセンスがある場合があるため、個別に確認してください。
MongoDB Community ServerはServer Side Public Licenseを使っています。ソースは利用できますが、Open Source Initiativeが承認するライセンスではありません。MongoDB Atlasと商用サポートにはベンダーの価格と利用規約が適用されます。データベース機能を組み込んだりサービスとして提供したりする組織は、寛容なオープンソースライセンスと同じだと考えず、適用される規約を法務担当者と確認すべきです。
マネージドデータベースは、より高い単価と引き換えに、自動プロビジョニング、パッチ適用、バックアップ、監視連携、フェイルオーバー処理の一部を提供します。それでも、スキーマの品質、遅いクエリ、接続管理、データ分類、アプリケーション復旧の責任は顧客側に残ります。
総所有コストは次の項目で見積もります。
- 本番、ステージング、開発、災害復旧、一時環境の数。
- 少なくとも今後12から24か月のデータとインデックスの増加。
- 必要なレプリカ数、リージョン、バックアップ保持期間、ネットワーク転送。
- ピーク時のスループット、ワーキングセット用メモリ、プロビジョニングするストレージ性能。
- マイグレーション、チューニング、障害対応、監査、復元訓練にかかるスタッフ時間。
すでにチームが十分に支援できるデータベースは、技術的に魅力的な代替案より安くなることがあります。トレーニング、新しい自動化、オンコール手順の改訂、移行リスクも実際のコストです。
ワークロード別のアプリケーション適合性
関係の多い基幹システムではPostgreSQLがより強力な標準選択です。一方MongoDBは、独立して所有される、構造にばらつきのあるドキュメントを扱う領域で価値を発揮します。Webアプリケーションやエンタープライズシステムといった大まかな分類より、具体的なワークフローのほうが適合性を明確にします。
SaaSのアカウントモデルには通常、組織、メンバーシップ、招待、ロール、サブスクリプション、請求書、権利、監査記録が含まれます。一意性とエンティティ横断のルールが中心であり、管理者はいずれローンチ時には想定していなかったレポートを求めます。このパターンにはPostgreSQLがよく合います。
商品カタログには、衣類、電子機器、工業部品、テナント独自のカテゴリごとに異なる属性セットがあります。MongoDBなら、スカスカな万能テーブルを作らずに、各商品を一貫したドキュメントとして保存できます。商品が価格テーブル、在庫トランザクション、ベンダー契約、リレーショナルなレポートにも深く関わる場合は、JSONBを使うPostgreSQLも競争力を保ちます。
コンテンツ管理の領域は、ブロック、ローカライズ、メタデータ、公開状態を含むドキュメントに自然に対応することが多いです。各エントリを1つの単位として読み取り、改訂するならMongoDBが適しています。編集権限、スケジューリング、コンテンツ間参照、レポートの要求が、ドキュメント構造の変化より重い場合はPostgreSQLが望ましいことがあります。
財務台帳、在庫引当、請求記録にはPostgreSQLが向いています。追記専用の設計だけでは、一意性、貸借の整合、照合クエリ、複数レコードにまたがる不変条件の必要性はなくなりません。
イベントとテレメトリーシステムでは、より詳細なテストが必要です。MongoDBはドキュメント型イベントを取り込め、PostgreSQLは追記の多いテーブルをパーティション分割できます。継続的な分析規模では、運用データベースから列指向のデータウェアハウスや専用時系列システムへデータを送ることがあります。保持期間、集計の時間枠、遅れて届くデータ、クエリのスキャンサイズが保存先を決めるべきです。
正本となるエンティティをPostgreSQLに残し、ドキュメント領域に独立した所有権とアクセスパターンがあるなら、ハイブリッドアーキテクチャは正当化できます。エンティティごとに1つの正本を割り当てます。アウトボックスまたは変更データキャプチャのプロセスで変更を公開し、冪等なコンシューマーを使い、遅延または重複配信を前提に計画してください。部分的な失敗の後にストア間で不整合が残る可能性があるため、同期的な二重書き込みは避けます。
実践的な決定方法
本番環境に近いデータを使った短い概念実証が、MongoDBとPostgreSQLの判断が接戦の場合に最も信頼できる解決方法です。汎用的な作成、読み取り、更新、削除のデモではなく、難しい部分に集中してください。
代表的なワークフローを3つ選びます。最も多いリクエスト、最も複雑なクエリ、最も厳しい正しさが求められる操作です。両方のデータベースで、各ワークフローを正直にモデル化してください。制限のないJSON列1つでPostgreSQLにドキュメントストアをまねさせたり、多数のコレクションにまたがる高度に正規化されたスキーマをMongoDBに再現させたりしないでください。
モデルの明確さ、正しさ、クエリの手間、測定したレイテンシ、運用の慣れ、復旧、セキュリティコントロール、予測コストで候補を採点します。ベンチマークの結果を見る前に、カテゴリへ重みを付けてください。財務アプリケーションでは、マイグレーション回避より整合性と監査可能性を重く見るべきです。使い捨てのコンテンツ試作なら、その逆の判断もありえます。
次のような前提に依存する設計は却下してください。
- 将来のすべてのクエリが、最初のAPIのアクセスパターンに従う。
- アプリケーション検証が、すべての書き込み経路で永遠に正しく実行される。
- 1つの大規模テナントが、中央値のテナントと同じように振る舞う。
- レプリケーションによってバックアップと復元訓練が不要になる。
- 2つ目のデータベースは、最初のデプロイメントがマネージドであるため運用コストがほとんどかからない。
一般的なトランザクションアプリケーションでは、PostgreSQLがより安全な出発点です。テーブル、SQL、制約、成熟したトランザクションモデル、JSONBのサポートにより、構造化データと選択的な半構造化データの両方に対応する余地があります。MongoDBを選ぶべきなのは、ドキュメントモデルによって設計が明確にシンプルになる場合、または統合された分散モデルが測定済みの要件に合う場合です。マイグレーションが面倒そうだからという理由ではありません。
Koder.aiプロジェクトへの適用
Koder.aiの主要スタックは、React、Go、PostgreSQL、モバイルアプリ向けのFlutterで構成されているため、ほとんどのKoder.aiプロジェクトではPostgreSQLが自然な出発点です。この標準構成は、チャットインターフェースでよく作られるWebサイト、CRM、ERP、モバイルアプリなどのトランザクションシステムに適しています。
Planning Modeでは、生成を始める前に、エンティティ、関係、一意性ルール、データ保持、高ボリューム操作を特定するべきです。安定したプロパティは型付き列に置きます。ビジネス固有の任意属性は、構造が本当に変化する場合にJSONBを使えます。
Koder.aiはソースコードのエクスポート、デプロイとホスティング、カスタムドメイン、スナップショット、ロールバックをサポートしています。スナップショットとアプリケーションのロールバックは、データベースのマイグレーション計画を置き換えるのではなく補完するべきです。互換性のないスキーマ変更後にアプリケーションコードを戻すと、古いコードが新しく書き込まれたデータを読めないことがあります。
生成されたGoサービスでは、データベース変更をレビュー済みのマイグレーションに保持し、移行期間中も安全にデプロイできるようにします。一般的な手順は、互換性のあるスキーマを追加し、両方の状態を理解するコードをデプロイし、データをバックフィルし、読み取りを切り替え、後のリリースで古い形式を削除することです。
Koder.aiは、データ配置の要件を支えるため、さまざまな国のAWSインフラストラクチャでアプリケーションを実行できます。データベース設計では、この判断をレプリカ、バックアップ、ログ、分析エクスポート、管理アクセスにも広げる必要があります。地理的な配置は、より広いプライバシーとガバナンス計画の中の1つのコントロールです。
PostgreSQLを使うプロジェクトにMongoDBを追加する場合も、ほかのアーキテクチャ依存関係と同じ基準に従うべきです。実装前に、ドキュメントが所有する領域、障害処理、同期経路、バックアップポリシー、運用責任を定義してください。
移行と導入のチェックリスト
データベース移行が成功したと言えるのは、チームがデータの完全性、アプリケーションの互換性、復元可能な切り替えを証明できるときです。構文の変換は作業の一部にすぎません。
まず、テーブルまたはコレクション、データ量、インデックス、制約、クエリパターン、保持ルール、すべての書き込み元を棚卸しします。リレーショナルな外部キーが参照に変わる、埋め込み配列が子テーブルに変わる、数値精度の違い、大文字小文字を区別する比較、タイムスタンプの扱いなど、直接変換できない意味を特定します。
本番データを移す前に、照合クエリを作ります。件数だけでは不十分です。テナントと日付ごとの合計を比べ、一意性を確認し、大きなレコードをサンプリングし、孤立した関係を調べ、該当する場合は業務レベルの残高を計算します。
制御された移行には通常、次の段階が含まれます。
- 最初の一括コピーを実行し、拒否または変換されたレコードを記録する。
- ログ、アウトボックス、変更データキャプチャの仕組みで、その後の変更を取得する。
- ユーザーに見える挙動を変えずに、シャドー読み取りまたはサンプルレスポンスの比較を行う。
- エラーと遅延を監視しながら、元に戻せるルーティング変更で切り替える。
- 照合とロールバック期間が完了するまで、古いストアを読み取り専用に保つ。
アプリケーションコードからの二重書き込みは、両方の書き込みが冪等で、部分的な失敗を明示的に照合する場合を除き危険です。1つのコミット済み正本と、再試行できる非同期配信レコードを優先してください。
切り替え後は、運用の基準値を作り直します。クエリプラン、接続プールのサイズ、アラートのしきい値、バックアップ時間、古いエンジンでの容量予測は自動的には引き継がれません。新しいデータベースで復元訓練を終え、チームが障害時に運用できて初めて、移行は完了です。
よくある質問
「どちらが最適か」で迷わず、MongoDBとPostgreSQLをどう選べばよいですか?
まず、データベースをワークロードとチームに合わせましょう。
- 関連するエンティティを扱い、結合やレポートを多用し、強い制約が必要なら PostgreSQL を選びます。
- レコードが自己完結したドキュメントとして扱え、構造が頻繁に変わり、オブジェクト全体をまとめて取得することが多いなら MongoDB を選びます。
システム内の領域ごとに必要なものが異なるなら、ハイブリッド構成も有効な選択肢です。
それぞれのデータベースに特に向くアプリケーションは何ですか?
大まかな目安は次のとおりです。
- 注文、請求、権限、監査証跡、在庫など、多対多の関係や厳密な整合性がある基幹システムには PostgreSQL が向いています。
- カタログ、コンテンツ、ユーザープロフィール、イベントペイロード、セッションや状態、テナント固有または急速に変化する属性など、ドキュメント中心の領域には MongoDB が向いています。
そのうえで、実際によく使うクエリと更新パターンで検証してください。
ネストしたデータでは、なぜMongoDBのほうが開発が速く感じられることが多いのですか?
MongoDBはネストしたオブジェクトを自然に保存できるため、1回の読み取りで集約全体を返せます。たとえば明細を埋め込んだ注文です。通信回数を減らし、初期段階の開発をシンプルにできます。
一方で、重複が増えやすく、同じ埋め込み情報を複数のドキュメントで更新する必要がある場合は更新が複雑になります。
PostgreSQLのリレーショナルモデルと制約から何が得られますか?
PostgreSQLはデータベースで正しさを守れます。
- 参照切れを防ぐ外部キー
- 不正な状態を防ぐ
CHECK制約とUNIQUE制約 - 複数テーブルにまたがる堅牢なトランザクション処理
これにより、見落としたコードパスから不整合なデータが入り込む可能性を減らせます。また、同時実行が多い業務ルールも長期的に考えやすくなります。
MongoDBに移行せず、PostgreSQLでドキュメントのようなデータを扱えますか?
はい。JSONB はよく「中間の選択肢」として使われます。一般的な構成は次のとおりです。
- ID、タイムスタンプ、状態、所有者など安定したフィールドは通常の列に置く
- 変化しやすい属性や任意属性は
JSONB列に置く - JSONB内を検索する必要があれば GIN インデックスを使う
これにより、柔軟な属性を扱いながらリレーショナルな整合性を維持できます。
PostgreSQLのJOINとMongoDBの埋め込み、$lookupはどう違いますか?
PostgreSQLでは結合が基本機能として扱われ、複数エンティティをまたぐクエリやアドホック分析では通常、より扱いやすくなります。
MongoDBは埋め込みによって結合を避ける設計を促します。コレクションをまたぐ結合が必要な場合は $lookup を使えますが、複雑なパイプラインは保守しにくくなり、適切にインデックスを張ったリレーショナル結合ほど予測しやすく拡張できないことがあります。
分析とレポーティングにはどちらのデータベースが向いていますか?
BIレポートや探索的なクエリが重要なら、一般にPostgreSQLが有利です。理由は次のとおりです。
- SQLは集計、ウィンドウ関数、CTEを含めて表現力が高い
- 多くの分析ツールがSQLを標準で扱える
- 複数エンティティにまたがるアドホックな問いを結合として自然に表現できる
MongoDBも、レポートがドキュメントの境界に沿うなら十分に使えます。ただし複数エンティティの分析では、より多くのパイプライン処理やETLが必要になることがあります。
実際のトランザクションと整合性保証は、どのくらい違いますか?
PostgreSQLは「トランザクションが中心」の設計で、複数の文やテーブルにまたがるACIDワークフロー、たとえば注文、在庫、台帳の更新に強みがあります。
MongoDBは標準で 単一ドキュメント 単位の原子性を持ちます。埋め込みに適した設計では特に効果的です。必要なら複数ドキュメントのトランザクションも使えますが、通常はオーバーヘッドや実用上の制約が増えます。中核となる整合性ルールが同時実行中の多数のレコードにまたがるなら、PostgreSQLのほうがシンプルに感じられることが多いでしょう。
性能とインデックスを比較する最も実践的な方法は何ですか?
実際のクエリを使い、クエリプランを確認してください。
- PostgreSQLでは
EXPLAIN (ANALYZE, BUFFERS)を使い、シーケンシャルスキャン、見積もり誤差、コストの高いソートを見つけます。 - MongoDBでは
explain()を使い、調べたドキュメント数と返された数を比べます。
どちらも複合インデックスと選択性が重要で、インデックスを増やしすぎると書き込み性能が大きく落ちます。
1つのシステムでMongoDBとPostgreSQLを両方使う意味はありますか?
はい。よくある現実的な分け方は次のとおりです。
- 制約が多い基幹エンティティには PostgreSQL
- 柔軟なコンテンツ、イベント量の多い機能、キャッシュや読み取りモデルには MongoDB
管理しやすくするには、エンティティごとに唯一の正本を定め、不変のIDを使い、アウトボックスやイベントのパターンで同期します。変更を計画しているなら、データベース移行チェックリストが移行作業の整理に役立ちます。