TechBlog

MySQL vs PostgreSQL:Webアプリ開発で使うデータベースの違いと選び方

by あくえり
#MySQL #PostgreSQL #データベース #比較 #SQL
MySQL vs PostgreSQL 比較ガイド
目次

MySQLとPostgreSQLの概要

MySQLは1995年、PostgreSQLは1996年に最初のリリースを迎えた老舗のオープンソースRDBMSです。現在も両者はWebアプリ開発の現場でトップシェアを争い続けています。

項目MySQL 8.4PostgreSQL 17
初版1995年1996年
ライセンスGPL v2(Community版) / 商用PostgreSQL License(BSDライク)
開発元Oracle(買収後)PostgreSQL Global Development Group
ACID準拠✓(InnoDBストレージエンジン)✓(完全対応)
SQLの標準準拠度中程度高い
最大DB容量無制限無制限

アーキテクチャの違い

MySQLのストレージエンジン

MySQLはストレージエンジンという仕組みでデータの保存方式を差し替えられます。現在の実質的なデフォルトはInnoDBで、ACID準拠・行レベルロック・外部キー制約に対応しています。

古いMyISAMはトランザション非対応のため、新規開発ではInnoDBしか選択肢がありません。

-- テーブル作成時にストレージエンジンを指定(デフォルトはInnoDB)
CREATE TABLE users (
  id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
  name VARCHAR(255) NOT NULL,
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

PostgreSQLの拡張型システム

PostgreSQLはカスタム型・演算子・インデックスメソッドを定義できる強力な拡張システムを持ちます。CREATE EXTENSIONで追加できる代表的な拡張が以下です。

-- pg_trgm: 正規表現・あいまい検索を高速化
CREATE EXTENSION IF NOT EXISTS pg_trgm;

-- uuid-ossp: UUID生成関数
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";

-- PostGIS: 地理空間データの処理(位置情報アプリに必須)
CREATE EXTENSION IF NOT EXISTS postgis;

PostgreSQLはCREATE TYPEでENUM以外にも独自の複合型・ドメイン型を定義できます。

JSON対応の比較

MySQLのJSON型

MySQL 5.7以降でJSON型が追加されました。バリデーションはあるものの、演算子や関数はPostgreSQLより少なめです。

-- MySQL: JSON型カラム
CREATE TABLE products (
  id INT PRIMARY KEY AUTO_INCREMENT,
  name VARCHAR(255) NOT NULL,
  attributes JSON
);

INSERT INTO products (name, attributes)
VALUES ('スニーカー', '{"size": 26, "color": "white", "tags": ["casual", "sports"]}');

-- JSON値の参照
SELECT name, attributes->>'$.color' AS color FROM products;

-- JSON配列の検索
SELECT name FROM products
WHERE JSON_CONTAINS(attributes, '"casual"', '$.tags');

PostgreSQLのJSONBとGIN

PostgreSQLにはjsonjsonbの2種類があります。jsonbはバイナリ形式で保存し、GINインデックスを使って高速に検索できるため、実用ではjsonb一択です。

-- PostgreSQL: JSONB型
CREATE TABLE products (
  id SERIAL PRIMARY KEY,
  name TEXT NOT NULL,
  attributes JSONB
);

INSERT INTO products (name, attributes)
VALUES ('スニーカー', '{"size": 26, "color": "white", "tags": ["casual", "sports"]}');

-- GINインデックスで検索を高速化
CREATE INDEX idx_products_attrs ON products USING GIN (attributes);

-- 演算子で検索(含むかどうか)
SELECT name FROM products
WHERE attributes @> '{"color": "white"}';

-- 配列内を検索
SELECT name FROM products
WHERE attributes->'tags' ? 'casual';

-- JSONB_PATH_QUERY(JSON Path)
SELECT name FROM products
WHERE jsonb_path_exists(attributes, '$.tags[*] ? (@ == "sports")');

JSONを多用するAPIでは、PostgreSQLのJSONBとGINインデックスが圧倒的に高機能です。

パフォーマンス特性

読み取り重視なら MySQL が有利な場合がある

MySQLはシンプルなSELECTクエリに特化した最適化がされており、Webアプリの典型的な「読み取り多・書き込み少」のワークロードで高いスループットを発揮します。

複雑なクエリはPostgreSQLが得意

JOINが多い複雑なクエリ・ウィンドウ関数・CTEの最適化はPostgreSQLが優れています。

-- PostgreSQL: WITH RECURSIVE(再帰CTE)でツリー構造を辿る
WITH RECURSIVE category_tree AS (
  -- ベースケース
  SELECT id, name, parent_id, 1 AS depth
  FROM categories
  WHERE parent_id IS NULL

  UNION ALL

  -- 再帰ケース
  SELECT c.id, c.name, c.parent_id, ct.depth + 1
  FROM categories c
  INNER JOIN category_tree ct ON c.parent_id = ct.id
)
SELECT * FROM category_tree ORDER BY depth, name;

MySQLも再帰CTEに対応していますが、PostgreSQLの方がクエリプランナーの最適化が優れているケースが多いです。

レプリケーション

MySQL

PRIMARY → REPLICA構成のレプリケーションは歴史が長く、実績があります。グループレプリケーションを使うと複数ノードへの同期書き込みが可能で、PlanetScaleはこれを基盤としています。

-- MySQLのレプリケーション確認
SHOW REPLICA STATUS\G

PostgreSQL

論理レプリケーション(PostgreSQL 10以降)でテーブル単位のサブスクリプションが可能です。またStreaming Replicationは非同期・同期両対応で、Supabaseのフェイルオーバーに使われています。

ライセンスと商用利用

項目MySQL CommunityPostgreSQL
ライセンスGPL v2PostgreSQL License
商用製品への組み込み別途商用ライセンス必要制限なし
OracleによるSaaSへの組み込み要確認自由
フォークMariaDB, Percona Server等なし(単一コードベース)

PostgreSQLは組み込み・商用利用の制限がなく、ライセンスリスクがゼロです。SaaS製品に組み込む場合はPostgreSQLの方が安心です。

主要ホスティングサービスとの相性

サービス対応DB特徴
PlanetScaleMySQL互換(Vitess)スキーマ変更が安全・ブランチ機能あり
SupabasePostgreSQLリアルタイム・Auth・Storage込み
NeonPostgreSQLServerless・ブランチ・自動スケール
AWS RDSMySQL / PostgreSQL 両対応マネージド・マルチAZ対応
AWS AuroraMySQL互換 / PostgreSQL互換RDSの最大5倍の読み取りスループット
RailwayMySQL / PostgreSQL 両対応簡単デプロイ・開発向け
RenderPostgreSQL無料プランあり

フロントエンドと一緒にデプロイするスタックならSupabase(PostgreSQL)かPlanetScale(MySQL互換)の二択になる場合が多いです。

プロジェクト規模別の選定基準

小規模・個人開発・スタートアップ初期

おすすめ: Supabase(PostgreSQL)

  • 無料プランで十分
  • Auth・Storage・Realtime機能が標準装備でバックエンドを減らせる
  • PostgreSQLの全機能が使える
# Supabase CLI でローカル環境を起動
npx supabase init
npx supabase start

中規模・Webアプリ(月間PV 10万〜100万程度)

おすすめ: AWS RDS(MySQL or PostgreSQL)

  • マネージドで運用コストが低い
  • マルチAZでフェイルオーバー対応
  • 複雑なビジネスロジックがあるならPostgreSQL

大規模・高トラフィック(月間PV 1000万以上)

おすすめ: Aurora MySQL or Aurora PostgreSQL

  • RDSの最大5倍の読み取りスループット
  • リードレプリカを最大15台まで追加可能
  • グローバル対応(Aurora Global Database)

選定フローチャート

  1. JSONデータを多用する? → PostgreSQL(JSONB + GINインデックスが強力)
  2. 地理空間データを扱う? → PostgreSQL(PostGIS拡張)
  3. 既存チームがMySQLに慣れている? → MySQL(学習コスト重視)
  4. Supabaseのエコシステムを使いたい? → PostgreSQL
  5. PlanetScaleのブランチ機能を使いたい? → MySQL互換

理論から学ぶデータベース実践入門 ―リレーショナルモデルによる効率的なSQL

MySQLを例にSQLとリレーショナルモデルの理論を体系的に解説。正規化・インデックス・トランザクションを原理から理解したいエンジニアに最適です。

※ アフィリエイトリンクを含みます

PostgreSQL全機能バイブル

PostgreSQLの基礎から高度な機能(JSONB・PostGIS・レプリケーション)まで網羅した決定版リファレンス。DBAからアプリ開発者まで使える実践的な内容です。

※ アフィリエイトリンクを含みます

まとめ

MySQLとPostgreSQLはどちらも成熟した優れたRDBMSです。最終的な選定は以下のポイントで判断しましょう。

  • PostgreSQLを選ぶ: 複雑なクエリ・JSON多用・地理空間・ライセンスリスクを避けたい・Supabase利用
  • MySQLを選ぶ: チームの習熟度・PlanetScale利用・シンプルなCRUD主体のWebアプリ

どちらのDBを使ったとしても、インデックス設計クエリの最適化がパフォーマンスに最も大きく影響します。DBの選定と同じくらい、EXPLAINでクエリプランを読む習慣をつけることが重要です。

共有: