PostgreSQL と MySQL の概要
リレーショナルデータベースの二大巨頭、PostgreSQLとMySQLを比較します。どちらもオープンソースで無料、長い歴史と大規模な導入実績を持ちます。
基本情報
| 項目 | PostgreSQL | MySQL |
|---|---|---|
| 開発元 | PostgreSQL Global Development Group | Oracle Corporation |
| 初回リリース | 1996年 | 1995年 |
| ライセンス | PostgreSQL License(BSD系) | GPL v2(商用はOracle) |
| 哲学 | 機能の豊富さ・標準準拠 | シンプルさ・速度 |
| 代表的な利用者 | Apple, Instagram, Spotify | Facebook, Twitter, Uber |
機能比較
| 機能 | PostgreSQL | MySQL |
|---|---|---|
| JSON/JSONB | ◎ ネイティブ対応 | ○ JSON型あり |
| 全文検索 | ◎ 内蔵(日本語対応) | ○ InnoDB全文検索 |
| GIS/地理空間 | ◎ PostGIS | ○ Spatial拡張 |
| マテリアライズドビュー | ○ 対応 | × 非対応 |
| CTE (WITH句) | ◎ 再帰CTE対応 | ○ 対応 |
| Window関数 | ◎ 豊富 | ○ 対応 |
| 配列型 | ○ 対応 | × 非対応 |
| Enum型 | ○ 対応 | ○ 対応 |
| ストアドプロシージャ | ○ PL/pgSQL等 | ○ 対応 |
| パーティショニング | ○ 宣言的 | ○ 対応 |
| レプリケーション | ○ 論理/物理 | ◎ 成熟 |
SQL の違い
文字列の扱い
-- PostgreSQL: シングルクォートのみ
SELECT 'Hello World';
SELECT "column_name" FROM users; -- ダブルクォートは識別子
-- MySQL: シングル/ダブルどちらもOK(デフォルト)
SELECT 'Hello World';
SELECT "Hello World"; -- これも文字列
SELECT `column_name` FROM users; -- バッククォートが識別子
UPSERT(INSERT or UPDATE)
-- PostgreSQL: ON CONFLICT
INSERT INTO users (email, name)
VALUES ('[email protected]', '田中')
ON CONFLICT (email)
DO UPDATE SET name = EXCLUDED.name;
-- MySQL: ON DUPLICATE KEY UPDATE
INSERT INTO users (email, name)
VALUES ('[email protected]', '田中')
ON DUPLICATE KEY UPDATE name = VALUES(name);
LIMIT + OFFSET
-- PostgreSQL
SELECT * FROM users ORDER BY id LIMIT 10 OFFSET 20;
-- MySQL(同じ構文が使える)
SELECT * FROM users ORDER BY id LIMIT 10 OFFSET 20;
-- MySQL独自構文
SELECT * FROM users ORDER BY id LIMIT 20, 10;
AUTO INCREMENT
-- PostgreSQL: SERIAL or GENERATED
CREATE TABLE users (
id SERIAL PRIMARY KEY,
-- or
id INTEGER GENERATED ALWAYS AS IDENTITY PRIMARY KEY
);
-- MySQL: AUTO_INCREMENT
CREATE TABLE users (
id INT AUTO_INCREMENT PRIMARY KEY
);
日付・時刻
-- PostgreSQL
SELECT NOW(); -- タイムスタンプ
SELECT CURRENT_DATE; -- 日付
SELECT EXTRACT(YEAR FROM NOW()); -- 年を抽出
SELECT '2026-03-31'::DATE; -- キャスト
-- MySQL
SELECT NOW(); -- 日時
SELECT CURDATE(); -- 日付
SELECT YEAR(NOW()); -- 年を抽出
SELECT CAST('2026-03-31' AS DATE); -- キャスト
JSON の扱い
PostgreSQL の JSONB
PostgreSQLの JSONB は非常に強力です:
-- JSONB カラムを持つテーブル
CREATE TABLE products (
id SERIAL PRIMARY KEY,
name TEXT NOT NULL,
attributes JSONB DEFAULT '{}'
);
-- データ挿入
INSERT INTO products (name, attributes) VALUES
('ノートPC', '{"brand": "Apple", "ram": 16, "tags": ["laptop", "mac"]}');
-- JSON内のフィールドで検索
SELECT * FROM products
WHERE attributes->>'brand' = 'Apple';
-- JSON内のフィールドでフィルタ(数値比較)
SELECT * FROM products
WHERE (attributes->>'ram')::int >= 16;
-- 配列の中を検索
SELECT * FROM products
WHERE attributes->'tags' ? 'laptop';
-- GIN インデックスで高速化
CREATE INDEX idx_products_attrs ON products USING GIN (attributes);
-- JSON パスクエリ(PostgreSQL 12+)
SELECT * FROM products
WHERE attributes @? '$.tags[*] ? (@ == "laptop")';
MySQL の JSON
-- JSON カラム
CREATE TABLE products (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(255) NOT NULL,
attributes JSON
);
-- JSON内のフィールドで検索
SELECT * FROM products
WHERE JSON_EXTRACT(attributes, '$.brand') = 'Apple';
-- ショートハンド
SELECT * FROM products
WHERE attributes->>'$.brand' = 'Apple';
-- JSON検索はインデックスが効きにくい(仮想カラムで対応)
ALTER TABLE products
ADD COLUMN brand VARCHAR(50)
GENERATED ALWAYS AS (attributes->>'$.brand') STORED;
CREATE INDEX idx_brand ON products (brand);
PostgreSQLの方がJSONの扱いが強力です。
パフォーマンス特性
読み取り性能
単純なSELECTクエリでは大きな差はありませんが、特性が異なります:
| シナリオ | PostgreSQL | MySQL |
|---|---|---|
| 単純なSELECT | ○ | ◎ |
| 複雑なJOIN | ◎ | ○ |
| サブクエリ | ◎ | ○ |
| 集計(GROUP BY) | ◎ | ○ |
書き込み性能
| シナリオ | PostgreSQL | MySQL |
|---|---|---|
| 単純なINSERT | ○ | ◎ |
| バルクINSERT | ○ | ◎ |
| UPDATE(大量) | ○ | ○ |
| MVCC効率 | ○ | ○ |
接続管理
PostgreSQL: プロセスベース(1接続=1プロセス)
→ PgBouncer等の接続プーラーが推奨
MySQL: スレッドベース(1接続=1スレッド)
→ 軽量で多数の接続を処理しやすい
拡張性
PostgreSQL の拡張機能
-- 拡張機能のインストール
CREATE EXTENSION IF NOT EXISTS "uuid-ossp"; -- UUID生成
CREATE EXTENSION IF NOT EXISTS "pg_trgm"; -- トライグラム全文検索
CREATE EXTENSION IF NOT EXISTS "postgis"; -- 地理空間データ
-- UUID生成
SELECT uuid_generate_v4();
-- あいまい検索
SELECT * FROM products
WHERE name % 'ノートパソコン' -- トライグラム類似検索
ORDER BY similarity(name, 'ノートパソコン') DESC;
主要な拡張機能:
| 拡張 | 機能 |
|---|---|
| PostGIS | 地理空間データ処理 |
| pg_trgm | トライグラム全文検索 |
| uuid-ossp | UUID生成 |
| pgcrypto | 暗号化関数 |
| pg_stat_statements | クエリ統計 |
| timescaledb | 時系列データ |
| pgvector | ベクトル検索(AI/ML) |
MySQL のプラグイン
MySQLもプラグインで拡張できますが、PostgreSQLほどの柔軟性はありません。
クラウドサービス
| サービス | PostgreSQL | MySQL |
|---|---|---|
| AWS | RDS, Aurora PostgreSQL | RDS, Aurora MySQL |
| GCP | Cloud SQL, AlloyDB | Cloud SQL |
| Azure | Azure Database for PostgreSQL | Azure Database for MySQL |
| サーバーレス | Neon, Supabase | PlanetScale |
ORM との相性
Prisma
// どちらもPrismaで使える
datasource db {
provider = "postgresql" // or "mysql"
url = env("DATABASE_URL")
}
Drizzle ORM
// PostgreSQL
import { pgTable, serial, text } from 'drizzle-orm/pg-core';
const users = pgTable('users', {
id: serial('id').primaryKey(),
name: text('name').notNull(),
});
// MySQL
import { mysqlTable, int, varchar } from 'drizzle-orm/mysql-core';
const users = mysqlTable('users', {
id: int('id').primaryKey().autoincrement(),
name: varchar('name', { length: 255 }).notNull(),
});
選定ガイド
PostgreSQL を選ぶべきケース
- 複雑なクエリ: JOIN、サブクエリ、CTEが多い
- JSON データ: JSONBの強力な機能が必要
- 地理空間データ: PostGISが必要
- 拡張性: カスタム型、関数、拡張機能が必要
- SQL標準準拠: 標準SQLに忠実なコードを書きたい
- ベクトル検索: pgvectorでAI/ML機能を統合
MySQL を選ぶべきケース
- シンプルなCRUD: 単純な読み書きが中心
- 高い同時接続数: 軽量な接続管理
- 既存の知見: チームがMySQLに精通している
- レプリケーション: 成熟したレプリケーション機能
- WordPress/PHP: PHPエコシステムとの親和性
まとめ
| 判断軸 | PostgreSQL | MySQL |
|---|---|---|
| 機能の豊富さ | ◎ | ○ |
| JSON対応 | ◎ | ○ |
| 学習コスト | ○ | ◎ |
| 単純な読み書き | ○ | ◎ |
| 拡張性 | ◎ | ○ |
| クラウド対応 | ◎ | ◎ |
2026年のWebアプリケーション開発では、PostgreSQLが第一選択になるケースが増えています。特にJSON対応、拡張機能、SQL標準準拠の面で優れています。一方、MySQLもシンプルなアプリケーションでは十分な選択肢です。
SQLクエリの結果をJSON形式で確認する際は、AssistyのJSONフォーマッターで見やすく整形できます。