目次
- TL;DR
- 1. 設計思想の違い
- 2. PostgreSQL が向いているケース
- 3. MySQL が向いているケース
- 4. よくある落とし穴
- 5. マネージドサービスの選択肢
- 6. 判断フローチャート
- 7. どちらを選んでも共通のベストプラクティス
- まとめ
TL;DR
| 迷ったら | 選ぶもの |
|---|---|
| 新規プロジェクトで特に制約がない | PostgreSQL |
| 既存資産・チームのノウハウが MySQL に寄っている | MySQL |
| 単純な CRUD 中心で、読み取りが多くレプリカで横に広げたい | MySQL(どちらでも可) |
| 複雑なクエリ・分析・JSON・地理空間・厳密な整合性が要る | PostgreSQL |
| WordPress などの MySQL 前提の OSS を使う | MySQL / MariaDB |
最近は「特別な理由がなければ PostgreSQL」がデファクトになりつつあります。ただし MySQL が劣っているわけではなく、運用実績・チームの慣れ・エコシステムが選定理由として最も重いことが多いです。
1. 設計思想の違い
| 観点 | MySQL (InnoDB) | PostgreSQL |
|---|---|---|
| 思想 | シンプル・高速・運用しやすさ重視 | 標準 SQL 準拠・拡張性・正確性重視 |
| 同時実行制御 | MVCC(undo ログ方式) | MVCC(追記型。古い行は VACUUM で回収) |
| デフォルト分離レベル | REPEATABLE READ | READ COMMITTED |
| 拡張性 | プラグインはあるが限定的 | Extension 文化が強い(PostGIS, pgvector, TimescaleDB など) |
| ライセンス | GPL(Oracle 所有)/ 商用版あり | PostgreSQL License(BSD 系、非常に緩い) |
2. PostgreSQL が向いているケース
- 複雑なクエリ・集計
- CTE(再帰含む)、ウィンドウ関数、
LATERAL、FILTER句などが充実 - オプティマイザがハッシュ結合・マージ結合などを柔軟に選び、複雑な JOIN に強い
- CTE(再帰含む)、ウィンドウ関数、
- JSON を本格的に扱う
jsonb+ GIN インデックスで、JSON 内部を検索条件に使っても速い
- データ型が豊富
- 配列、範囲型(
tstzrangeなど)、UUID、INET、列挙型、ドメイン型、複合型 - 範囲型 + 排他制約(
EXCLUDE)で「予約の重複禁止」を DB レベルで保証できる
- 配列、範囲型(
- 地理空間データ → PostGIS は事実上の業界標準
- ベクトル検索(RAG など) →
pgvectorで既存 DB にそのまま追加できる - 厳密な整合性
- DDL もトランザクション内で実行・ロールバック可能(マイグレーション失敗時に安全)
- CHECK 制約、部分インデックス、式インデックス、遅延制約などが充実
- 分析系ワークロードとの兼用
- パラレルクエリ、マテリアライズドビュー、パーティショニング
3. MySQL が向いているケース
- シンプルな OLTP(主キー検索・単純な CRUD)が大半
- クラスタ化インデックス(主キー順に行を格納)により、主キー検索・範囲スキャンが速い
- 読み取り中心で、レプリカで水平に広げたい
- レプリケーションの運用実績・ツール(Orchestrator, ProxySQL, Vitess など)が豊富
- 大規模シャーディング
- Vitess(YouTube 発)や PlanetScale など、MySQL 互換で大規模に水平分割する選択肢が成熟
- 既存資産・人材
- WordPress、Magento などの OSS は MySQL 前提
- 日本では特に Web 系で MySQL の運用ノウハウを持つエンジニアが多い
- 運用の手軽さ
- VACUUM のようなメンテナンスを意識する必要が少ない
- 更新が非常に多いテーブルでも、PostgreSQL のような肥大化(bloat)が起きにくい
4. よくある落とし穴
MySQL
- 文字コード:
utf8は 3 バイトで絵文字が入らない。必ずutf8mb4を使う - sql_mode:緩い設定だと不正値が黙って切り詰め・変換される。
STRICT_TRANS_TABLESを含む厳格モードを維持する - 照合順序(collation):大文字小文字・全角半角・濁点の区別がデフォルトでは期待と違うことがある(例:
ハとパが同一視される照合順序がある)。要件に合わせて明示する - DDL はトランザクション外:マイグレーションが途中で失敗すると中途半端な状態が残る
- 大きなテーブルの ALTER:Online DDL の対応範囲を確認するか、
gh-ost/pt-online-schema-changeを使う
PostgreSQL
- VACUUM / autovacuum:更新・削除が多いテーブルは bloat しやすい。autovacuum の設定を監視・調整する
- トランザクション ID 周回(wraparound):VACUUM が長期間回らないと深刻な障害になる。監視必須
- コネクションが重い:1 接続 = 1 プロセス。PgBouncer などのコネクションプーラーはほぼ必須
- 長時間トランザクション:古い行が回収できなくなり bloat の原因に。
idle_in_transaction_session_timeoutを設定する - 大文字の識別子:ダブルクォートで囲まないと小文字に変換される。テーブル名・カラム名は snake_case の小文字に統一する
5. マネージドサービスの選択肢
どちらも主要クラウドで提供されているため、クラウド選定が DB 選定の制約になることはほぼありません。
| MySQL | PostgreSQL | |
|---|---|---|
| AWS | RDS for MySQL, Aurora MySQL | RDS for PostgreSQL, Aurora PostgreSQL |
| Google Cloud | Cloud SQL for MySQL | Cloud SQL for PostgreSQL, AlloyDB |
| Azure | Azure Database for MySQL | Azure Database for PostgreSQL |
| その他 | PlanetScale, TiDB(MySQL 互換) | Supabase, Neon, CockroachDB / YugabyteDB(PostgreSQL 互換) |
各サービスの対応バージョンや料金は変わるため、採用時に公式ドキュメントで確認してください。
6. 判断フローチャート
既存システム・OSS が MySQL 前提?
├─ Yes → MySQL
└─ No
│
チームの運用経験が片方に大きく偏っている?
├─ Yes → 慣れている方(運用できることが最優先)
└─ No
│
JSON検索 / 地理空間 / ベクトル検索 / 複雑な分析クエリ が必要?
├─ Yes → PostgreSQL
└─ No
│
超大規模な水平シャーディングが前提(Vitess 等を使いたい)?
├─ Yes → MySQL
└─ No → PostgreSQL(汎用性・拡張性で有利)
7. どちらを選んでも共通のベストプラクティス
- 主キーは必ず定義する(MySQL は特に、主キーがないと性能・レプリケーションに悪影響)
- ORM 任せにせず、実行計画(
EXPLAIN)を確認する習慣をつける - スロークエリログを有効にして定期的に見る
- マイグレーションはツールで管理(Flyway, Liquibase, Rails/Django/Prisma のマイグレーションなど)
- バックアップは「リストアできること」まで定期的に検証する
- DB 固有機能への依存は意識的に:便利な固有機能は積極的に使ってよいが、使った箇所を把握しておく
- タイムゾーンは UTC で保存(PostgreSQL は
timestamptz、MySQL は接続のタイムゾーン設定に注意)
まとめ
- 技術的な表現力・拡張性 → PostgreSQL が有利
- シンプルさ・大規模水平分割の実績・既存エコシステム → MySQL が有利
- 実務では 「チームが運用できるか」 が最も重要な選定基準
- 白紙から選ぶなら PostgreSQL が無難なデフォルト