Skip Navigation
Show nav
Dev Center
  • Get Started
  • ドキュメント
  • Changelog
  • Search
  • Get Started
    • Node.js
    • Ruby on Rails
    • Ruby
    • Python
    • Java
    • PHP
    • Go
    • Scala
    • Clojure
    • .NET
  • ドキュメント
  • Changelog
  • More
    Additional Resources
    • Home
    • Elements
    • Products
    • Pricing
    • Careers
    • Help
    • Status
    • Events
    • Podcasts
    • Compliance Center
    Heroku Blog

    Heroku Blog

    Find out what's new with Heroku on our blog.

    Visit Blog
  • Log inorSign up
View categories

Categories

  • Heroku のアーキテクチャ
    • Dyno (アプリコンテナ)
      • Dyno Management
      • Dyno Concepts
      • Dyno Behavior
      • Dyno Reference
      • Dyno Troubleshooting
    • スタック (オペレーティングシステムイメージ)
    • ネットワーキングと DNS
    • プラットフォームポリシー
    • プラットフォームの原則
  • Developer Tools
    • コマンドライン
    • Heroku VS Code Extension
  • デプロイ
    • Git を使用したデプロイ
    • Docker によるデプロイ
    • デプロイ統合
  • 継続的デリバリーとインテグレーション
    • 継続的統合
  • 言語サポート
    • Node.js
      • Working with Node.js
      • Node.js Behavior in Heroku
      • Troubleshooting Node.js Apps
    • Ruby
      • Rails のサポート
      • Bundler の使用
      • Working with Ruby
      • Ruby Behavior in Heroku
      • Troubleshooting Ruby Apps
    • Python
      • Working with Python
      • Python でのバックグランドジョブ
      • Python Behavior in Heroku
      • Django の使用
    • Java
      • Java Behavior in Heroku
      • Working with Java
      • Maven の使用
      • Spring Boot の使用
      • Troubleshooting Java Apps
    • PHP
      • PHP Behavior in Heroku
      • Working with PHP
    • Go
      • Go の依存関係管理
    • Scala
    • Clojure
    • .NET
      • Working with .NET
  • データベースとデータ管理
    • Heroku Postgres
      • Postgres の基礎
      • Postgres スターターガイド
      • Postgres のパフォーマンス
      • Postgres のデータ転送と保持
      • Postgres の可用性
      • Postgres の特別なトピック
      • Migrating to Heroku Postgres
    • Heroku Data For Redis
    • Apache Kafka on Heroku
    • その他のデータストア
  • AI
    • Working with AI
    • Heroku Inference
      • Inference API
      • Quick Start Guides
      • AI Models
      • Inference Essentials
    • Vector Database
    • Model Context Protocol
  • モニタリングとメトリクス
    • ログ記録
  • アプリのパフォーマンス
  • アドオン
    • すべてのアドオン
  • 共同作業
  • セキュリティ
    • アプリのセキュリティ
    • ID と認証
      • シングルサインオン (SSO)
    • Private Space
      • インフラストラクチャネットワーキング
    • コンプライアンス
  • Heroku Enterprise
    • Enterprise Accounts
    • Enterprise Team
    • Heroku Connect (Salesforce 同期)
      • Heroku Connect の管理
      • Heroku Connect のリファレンス
      • Heroku Connect のトラブルシューティング
  • パターンとベストプラクティス
  • Heroku の拡張
    • Platform API
    • アプリの Webhook
    • Heroku Labs
    • アドオンのビルド
      • アドオン開発のタスク
      • アドオン API
      • アドオンのガイドラインと要件
    • CLI プラグインのビルド
    • 開発ビルドパック
    • Dev Center
  • アカウントと請求
  • トラブルシューティングとサポート
  • Salesforce とのインテグレーション
  • データベースとデータ管理
  • Heroku Postgres
  • Postgres のパフォーマンス
  • MVCC による PostgreSQL の並列性

MVCC による PostgreSQL の並列性

日本語 — Switch to English

最終更新日 2022年12月28日(水)

Table of Contents

  • MVCC の仕組み
  • MVCC の欠点

Postgres の大きなセールスポイントの 1 つは、並列性を処理する仕組みです。ルールはシンプルです。読み取りは決して書き込みをブロックせず、その逆も同様です。Postgres では、多版型同時実行制御 (Multi Version Concurrency Control) と呼ばれるメカニズムを介してこれを実現します。この手法は Postgres に特有のものではなく、Oracle、Berkeley DB、CouchDB、その他多数​のデータベースが何らかの形で MVCC を実装しています。Postgres における MVCC の実装の仕組みを理解することは、並列性の高いアプリを PostgreSQL で設計するにあたって重要です。これは実際には、困難な問題に対する洗練されたシンプルなソリューションです。

MVCC の仕組み

Postgres では、すべてのトランザクションが XID と呼ばれるトランザクション ID を取得します。これには、挿入、更新、削除のように 1 つのステートメントから成るトランザクションに加えて、ステートメントのグループを BEGIN​ - COMMIT​ で明示的にラップしたものが含まれます。トランザクションが開始すると、Postgres は XID をインクリメントし、現在のトランザクションにその XID を割り当てます。Postgres はシステムのすべての行のトランザクション情報も保存し、この情報を利用してトランザクションからの行の可視性が決定されます。

たとえば、行を挿入すると、Postgres によって XID が行に保存され、xmin​ という名前が付けられます。コミット済みで、現在のトランザクションの XID よりも xmin​ が小さいすべての行がトランザクションから可視になります。つまり、トランザクションを開始して行を挿入したとしても、そのトランザクションが COMMIT​ しない限り、その行は他のトランザクションから可視になりません。そのトランザクションがコミットし、他のトランザクションが作成されると、後者は xmin < XID​ の条件を満たしており、行を作成したトランザクションは完了しているので、新しい行は後者に対して可視になります。

DELETE​ と UPDATE​ でも同様のメカニズムが発生しますが、これらのケースに限り、Postgres は可視性を決定するために xmax​ の値を各行に保存します。次の図は、行の挿入と読み取りを行う 2 つの並列トランザクションと、トランザクションの分離に MVCC がどのような役割を果たすか示しています。

以下の図で前提としているのは次の DDL です。

CREATE TABLE numbers (value int);

MVCC による読み取り/書き込みの分 離

日常の運用の中で xmin​ や xmax​ の値を目にすることはありませんが、これらの値は Postgres に問い合わせればすぐに確認できます。

SELECT *, xmin, xmax FROM numbers;

現在のトランザクションの XID も取得できます。

SELECT txid_current();

簡単です。

さて、読者の皆さんはきっとこう思っているでしょう。「2 つのトランザクションが同じ行を同時に更新したらどうなるのか?」ここでトランザクション分離レベルの出番です。Postgres では基本的に、この状況への対処方法を制御するための 2 つのモデルをサポートしています。デフォルトの READ COMMITTED​ は、最初のトランザクションが完了した後に行を読み取り、ステートメントを実行します。待機している間に行が変更された場合、基本的には最初からやり直します。たとえば、WHERE​ 句を伴う UPDATE​ を実行した場合、最初のトランザクションのコミット後に WHERE​ 句が再実行され、WHERE​ 句の条件がまだ満たされていれば UPDATE​ が実行されます。次に示す、行を変更する 2 つのトランザクションの例では、最初の UPDATE​ が原因で、2 番目のトランザクションの WHERE​ 句が行を返しません。したがって、2 番目のトランザクションはどの行も一切更新しません。

READ COMMITTED のトランザクション分離

この動作をさらにきめ細かく制御する必要がある場合、トランザクション分離レベルを SERIALIZABLE​ に設定できます。この戦略では “変更しようとしている行が別のトランザクションによって変更されている場合は、試すこともしない” という方針を採るので、上記のシナリオは単に失敗し、Postgres の応答はエラーメッセージ ERROR: could not serialize access due to concurrent update​ (同時更新が原因でアクセスをシリアル化できませんでした) になります。このエラーを処理して再試行するか、諦めた方が良いと判断してそうするかはアプリ次第です。

SERIALIZABLE のトランザクション分離

MVCC の欠点

MVCC とトランザクション分離が実際にどのように機能するかを理解したので、SERIALIZABLE​ の分離レベルが適している問題を解決するために、別のツールを追加しました。MVCC の利点は明らかですが、いくつかの欠点もあります。

可視である行のセットはトランザクションごとに異なるため、Postgres では、古くなっている可能性があるレコードを維持する必要があります。UPDATE​ が実際には新しい行を作成するのはこれが理由であり、DELETE​ が実際には​行を削除せず、行を削除済みとマークして XID 値を適切に設定するだけである理由も同じです。トランザクションが完了すると、将来のどのトランザクションからも可視になる可能性がない行がデータベースに残ることになります。これらはデッドロー (dead row) と呼ばれます。MVCC に由来するもう 1 つの問題として、トランザクション ID はただ大きくなり続けることしかできません。32 ビットであり、サポートできるのは 約 40 億トランザクション “のみ"です。最大値に達すると、XID は最小値に戻って (ラップアラウンドして) ゼロから再開します。突然、すべての​行が将来のトランザクションにあるかのように見え、新しいトランザクションはそれらの行への可視性を得られなくなります。

デッドローとトランザクション XID ラップアラウンドの問題はどちらも VACUUM​ によって解決されます。これは定期的なメンテナンスですが、幸いにも Postgres には、設定可能な頻度で実行される auto_vacuum デーモンが付属しています。デプロイが異なれば必要なバキューム頻度も異なるため、これを注視することは重要です。VACUUM​ の実際の動作について詳しくは、Postgres のドキュメント​を参照してください。Heroku での処理​方法も参照してください。

関連カテゴリー

  • Postgres のパフォーマンス
高コストなクエリ PostgreSQL インデックスの効率的な使用

Information & Support

  • Getting Started
  • Documentation
  • Changelog
  • Compliance Center
  • Training & Education
  • Blog
  • Support Channels
  • Status

Language Reference

  • Node.js
  • Ruby
  • Java
  • PHP
  • Python
  • Go
  • Scala
  • Clojure
  • .NET

Other Resources

  • Careers
  • Elements
  • Products
  • Pricing
  • RSS
    • Dev Center Articles
    • Dev Center Changelog
    • Heroku Blog
    • Heroku News Blog
    • Heroku Engineering Blog
  • Twitter
    • Dev Center Articles
    • Dev Center Changelog
    • Heroku
    • Heroku Status
  • Github
  • LinkedIn
  • © 2025 Salesforce, Inc. All rights reserved. Various trademarks held by their respective owners. Salesforce Tower, 415 Mission Street, 3rd Floor, San Francisco, CA 94105, United States
  • heroku.com
  • Legal
  • Terms of Service
  • Privacy Information
  • Responsible Disclosure
  • Trust
  • Contact
  • Cookie Preferences
  • Your Privacy Choices