PostgreSQL入門:PostgreSQLとは何か、そしてなぜそれを選ぶのか

PostgreSQLは世界で最も先進的なオープンソースのリレーショナルデータベースです。信頼性、拡張性、標準準拠で知られ、Apple、Instagram、Spotifyなどのグローバルリーダーに信頼されています。

1. 学習内容


2. フルスタック開発者の実体験

(1) 悩み:データベース選定は混乱する

Aliceはフルスタック開発者で、彼女の会社は新しいEコマースプロジェクトを立ち上げようとしています。技術選定の会議で、チームはMySQLとPostgreSQLの間で議論を交わしました:

彼女は客観的で包括的な比較を必要とし、それに基づいて決定を下さなければなりませんでした。

(2) PostgreSQLのソリューション

PostgreSQLは、従来のリレーショナル検索からJSONドキュメントストレージ、全文検索からベクトル検索まで、単一のデータベースでほとんどのビジネスニーズをカバーします。余分なミドルウェアは不要です:

SQL
-- PostgreSQL:複数のユースケースを1つのデータベースで

-- 1. 従来のリレーショナル検索
SELECT u.name, COUNT(o.id) AS order_count
FROM users u
LEFT JOIN orders o ON u.id = o.user_id
GROUP BY u.name;

-- 2. JSONBの柔軟なストレージ(MongoDB不要)
INSERT INTO products (name, attributes)
VALUES ('ランニングシューズ', '{"color": "red", "size": 42, "tags": ["sport", "outdoor"]}'::jsonb);

-- 3. 全文検索(Elasticsearch不要)
SELECT name FROM products
WHERE to_tsvector('english', name) @@ to_tsquery('english', 'running & shoes');

(3) 得られた成果

AliceはPostgreSQLを選ぶことが以下の意味を持つと気づきました:


3. データベースとは何か

データベースとは、データを構造化された方法で整理、保存、管理するシステムです。データベースがなければ、アプリケーションのデータはメモリ上にしか存在せず、プログラムを閉じた瞬間に消えてしまいます。

(1) リレーショナル vs 非リレーショナルデータベース

観点 リレーショナル(RDBMS) 非リレーショナル(NoSQL)
データモデル テーブル(行+列)、厳格なスキーマ ドキュメント / キーバリュー / グラフ / ワイドカラム、柔軟なスキーマ
クエリ言語 SQL(標準化) 独自のAPI
トランザクション ACIDによる強整合性 ほとんどが結果整合性のみ
事例 PostgreSQL、MySQL、Oracle MongoDB、Redis、Cassandra
ユースケース 複雑な検索、トランザクション処理、高整合性ニーズ 高スループット、柔軟な構造、迅速な反復
スケーリング 主に垂直 主に水平
100%
graph TB
    DB[データベース] --> RDBMS[リレーショナルDB<br/>SQL + ACID]
    DB --> NoSQL[NoSQL<br/>柔軟なスキーマ]
    RDBMS --> PG[PostgreSQL]
    RDBMS --> MY[MySQL]
    RDBMS --> OR[Oracle]
    NoSQL --> MGO[MongoDB<br/>ドキュメント]
    NoSQL --> RED[Redis<br/>キーバリュー]
    NoSQL --> CAS[Cassandra<br/>ワイドカラム]
💡 ヒント: PostgreSQLはリレーショナルデータベースですが、JSONB型によってドキュメントデータベースのように柔軟な構造を保存できます。そのためPGは「1つのデータベースで3つを置き換える」と言われています。


4. PostgreSQLの歴史

(1) POSTGRESからPostgreSQLへ

100%
graph LR
    A["1986年<br/>POSTGRESプロジェクト<br/>UC Berkeley"] --> B["1995年<br/>Postgres95<br/>SQLサポート追加"]
    B --> C["1996年<br/>PostgreSQL 6.0<br/>オープンソースリリース"]
    C --> D["2010年代<br/>JSONB / CTE / ウィンドウ<br/>関数 / FDW"]
    D --> E["2024年<br/>PostgreSQL 17<br/>現行LTSリリース"]
マイルストーン 意義
1986 POSTGRESプロジェクト開始 Michael StonebrakerがUC Berkeleyで開始、Ingresに触発
1995 Postgres95リリース SQL言語サポートを追加(PostQUELクエリ言語を置き換え)
1996 PostgreSQL 6.0 正式にPostgreSQLに改名、オープンソースとしてリリース
2005 バージョン8.0 ネイティブWindowsサポート、セーブポイント、二相コミット
2012 バージョン9.2 JSONサポート(9.4でJSONBにアップグレード)、範囲型
2016 バージョン9.6 並列クエリ、フレーズ全文検索
2017 バージョン10.0 宣言的パーティショニング、論理レプリケーション、SCRAM認証
2022 バージョン15.0 MERGEコマンド(SQL標準UPSERT)
2024 バージョン17.0 現行LTSリリース、論理レプリケーション強化、完全なSQL/JSON標準

(2) PostgreSQLの設計思想

PostgreSQLの核となる設計思想は、次の4つの言葉に集約できます:

原則 具体化されている点
標準準拠 SQL標準(SQL:2023)に厳格に準拠し、ほとんどの標準機能をサポート
拡張性 カスタム型、関数、インデックスメソッド、手続き言語をサポート(Extensions経由)
信頼性 ACIDトランザクション、MVCC同時実行制御、WAL先行書き込みログ — デフォルトでデータが失われない
コミュニティ主導 単一企業の支配を受けず、世界中の1000人以上のコントリビューターが参加、真のオープンソース
📌 ポイント: PostgreSQLは「誰かのPostgreSQL」ではありません。PostgreSQLグローバル開発グループによって維持され、単一企業の支配を受けません。これはMySQL(Oracleが支配)との明確な対比です。


5. PostgreSQL vs MySQL

これはAliceと彼女のチームが最も気にしていたことです。以下に複数の観点からの客観的な比較を示します:

観点 PostgreSQL MySQL
アーキテクチャ プロセスモデル(1接続1プロセス) スレッドモデル(1接続1スレッド)
同時実行性 MVCC(マルチバージョン同時実行制御):読み取りと書き込みが互いにブロックしない 主にテーブルロック、InnoDBは行ロックだが範囲は限定的
SQL標準 SQL:2023に厳格準拠 部分準拠、MySQL固有の構文が多い
JSONサポート JSONB(バイナリス��レージ、インデックス検索が非常に高速) JSON(テキストストレージ、機能は限定的)
全文検索 組み込みのtsvector/tsquery、多言語サポート FULLTEXTインデックス、基本機能
インデックス型 6種類(B-Tree / GIN / GiST / BRIN / SP-GiST / Hash) 3種類(B-Tree / Hash / Fulltext)
拡張エコシステム CREATE EXTENSIONでワンステップインストール(pgvector / PostGISなど) 同等の仕組みなし
パーティショニング 宣言的パーティショニング(RANGE / LIST / HASH、PG 10+) パーティションテーブル(8.0+)、構文が冗長
レプリケーション ストリーミング+論理レプリケーション(テーブル単位でレプリケート) マスタースレーブレプリケーション(インスタンス全体)
バックアップ PITRポイントインタイムリカバリ(秒単位) binlogリプレイ(粗い粒度)
ライセンス PostgreSQLライセンス(BSDライク、非常に寛容) GPL(商用制限あり)
複雑なクエリ ウィンドウ関数 / 再帰CTE / LATERAL JOINをネイティブサポート 8.0+でサポートされるがPGより弱い
運用 多くの設定オプション、チューニングの余地が大きい すぐに使える、運用がシンプル
市場シェア DB-Enginesで7年連続最も成長しているデータベース 世界最大のインストールベース

▶ サンプル:UPSERT構文の比較

SQL
-- PostgreSQL:INSERT ON CONFLICT(より柔軟)
INSERT INTO users (email, name)
VALUES ('alice@example.com', 'Alice')
ON CONFLICT (email)
DO UPDATE SET name = EXCLUDED.name, updated_at = NOW()
RETURNING id, name, updated_at;
-- RETURNING句は影響を受けた行を返す(MySQLには同等のものがない)

Output:

TEXT
INSERT 0 1
SQL
-- MySQL:ON DUPLICATE KEY UPDATE(柔軟性が低い)
INSERT INTO users (email, name)
VALUES ('alice@example.com', 'Alice')
ON DUPLICATE KEY UPDATE name = VALUES(name), updated_at = NOW();
-- RETURNING句がないため、結果を得るには別途SELECTが必要

▶ サンプル:JSONBクエリの比較

SQL
-- PostgreSQL:GINインデックス付きJSONB(高速なインデックス検索)
SELECT name FROM products
WHERE attributes @> '{"color": "red"}'::jsonb;
-- @> は「含む」演算子、GINインデックスを使用

Output:

TEXT
 id | name     | value 
----+----------+-------
  1 | example  | 42
(1 row)
SQL
-- MySQL:JSON関数(このパターンではインデックスサポートなし)
SELECT name FROM products
WHERE JSON_CONTAINS(attributes, '"red"', '$.color');
-- インデックスなし、▶ルテーブルスキャン

▶ サンプル:全文検索の比較

SQL
-- PostgreSQL:ランキング付き組み込み全文検索
SELECT name, ts_rank(to_tsvector('english', name || ' ' || description),
                     to_tsquery('english', 'red & shoes')) AS rank
FROM products
WHERE to_tsvector('english', name || ' ' || description)
      @@ to_tsquery('english', 'red & shoes')
ORDER BY rank DESC;

Output:

TEXT
 id | name     | value 
----+----------+-------
  1 | example  | 42
(1 row)
SQL
-- MySQL:基本的なFULLTEXT検索(ランキングの柔軟性なし)
SELECT name FROM products
WHERE MATCH(name, description) AGAINST('red shoes' IN BOOLEAN MODE);
⚠️ 注意: MySQLはシンプルなシナリオ(単一テーブルCRUD、小規模プロジェクト)では習得が容易です。PostgreSQLの強みは複雑なクエリ、データ整合性、高度な機能にあります。誇大広告ではなく、プロジェクトのニーズに基づいて選択してください。


6. PostgreSQLの主要な強み

(1) ACIDトランザクション

ACIDはデータの信頼性を保証する4つの特性です:

特性 正式名称 意味 PostgreSQLの実装
A Atomicity(原子性) オール・オア・ナッシング:トランザクションは完全に成功するか完全にロールバックする WAL先行書き込みログ
C Consistency(一貫性) トランザクションの前後でデータベースは有効な状態を保つ 制約 / トリガー / 型チェック
I Isolation(分離性) 同時実行トランザクションが互いに干渉しない MVCCマルチバージョン同時実行制御
D Durability(永続性) コミットされたデータは決して失われない WAL + fsync

(2) MVCCマルチバージョン同時実行制御

MVCCはPostgreSQLの同時実行性の核心です。読み取りは書き込みをブロックせず、書き込みは読み取りをブロックしません:

シナリオ MySQL(InnoDB) PostgreSQL(MVCC)
読み書きの同時実行 共有/排他ロック、ブロックの可能性あり 読み取りはスナップショットを見る、書き込みは新しいバージョンを作成 — ブロックなし
長時間トランザクションの影響 他のトランザクションをブロック ブロックなし、古いバージョンのみ保持
一貫性読み取り MVCCが必要だが実装が複雑 自然なスナップショット分離

(3) 拡張性

PostgreSQLの拡張メカニズム(CREATE EXTENSION)は最大のエコシステムの強みです:

拡張 機能 置き換えるミドルウェア
pgvector ベクトル検索 / AIエンベディング Pinecone / Weaviate
PostGIS 地理空間クエリ MongoDB Geo
pg_trgm あいまい検索 Elasticsearch
pgcrypto 暗号化関数 アプリケーション層の暗号化
uuid-ossp UUID生成 アプリケーション層の生成
postgres_fdw クロスデータベースクエリ ETLツール

▶ サンプル:拡張機能のインストールと使用

SQL
-- 利用可能な拡張を確認
SELECT name, default_version, installed_version
FROM pg_available_extensions
WHERE name IN ('uuid-ossp', 'pg_trgm', 'pgcrypto');

-- 拡張をインストール
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";

-- 拡張を使ってUUIDを生成
SELECT uuid_generate_v4();
-- 出力:550e8400-e29b-41d4-a716-446655440000 のような一意のUUID

Output:

TEXT
CREATE TABLE

▶ サンプル:FILTERによる条件付き集計

SQL
-- PostgreSQL:条件付き集計のためのFILTER句(SQL標準)
SELECT
    store_id,
    COUNT(*) AS total_orders,
    COUNT(*) FILTER (WHERE status = 'completed') AS completed_orders,
    COUNT(*) FILTER (WHERE status = 'cancelled') AS cancelled_orders
FROM orders
GROUP BY store_id;

Output:

TEXT
 count 
-------
     5
(1 row)
SQL
-- MySQL:SUM(IF()) または SUM(CASE) の回避策が必要
SELECT
    store_id,
    COUNT(*) AS total_orders,
    SUM(IF(status = 'completed', 1, 0)) AS completed_orders,
    SUM(IF(status = 'cancelled', 1, 0)) AS cancelled_orders
FROM orders
GROUP BY store_id;

7. PostgreSQLの一般的なユースケース

シナリオ PGの機能
Eコマース JSONB商品属性 + 全文検索 + パーティショニング 動的なSKU属性、商品検索、月次パーティション注文
SaaSマルチテナント RLS行レベルセキュリティ + スキーマ分離 1つのデータベースで多数のテナントにサービス、行レベルポリシーでデータ分離
データ分析 ウィンドウ関数 + マテリアライズドビュー + CTE ユーザーリテンション分析、売上トレンドレポート、複雑な統計
AI / レコメンデーション pgvectorベクトル検索 商品類似度、セマンティック検索、RAGアプリ
GISサービス PostGIS拡張 地図アプリ、距離計算、ルート計画
金融 ACID + 3レベルの分離 + PITR 送金、照合、ポイントインタイムリカバリ
コンテンツ管理 全文検索 + JSONB 記事検索、タグ管理、柔軟なコンテンツ

▶ サンプル:Eコマース — 商品属性のJSONB活用

SQL
-- 商品ごとに異なる属性がある場合
-- 属性タイプごとに個別のテーブルや列は不要

INSERT INTO products (name, price, attributes) VALUES
    ('ランニングシューズ', 89.99, '{"color": "red", "size": 42, "weight_grams": 280}'::jsonb),
    ('ノートパソコン', 1299.00, '{"cpu": "M3", "ram_gb": 16, "screen_inch": 14}'::jsonb),
    ('コーヒー豆', 24.50, '{"origin": "Colombia", "roast": "medium", "weight_kg": 1}'::jsonb);

-- クエリ:100ドル未満の赤色の商品をすべて検索
SELECT name, price, attributes
FROM products
WHERE price < 100
  AND attributes @> '{"color": "red"}'::jsonb;

Output:

TEXT
     name      | price  |                 attributes
---------------+--------+--------------------------------------------
 ランニングシューズ |  89.99 | {"color": "red", "size": 42, "weight_grams": 280}

8. 完全な例:データベース選定の決定フロー

SQL
-- ============================================
-- 総合的な例:PostgreSQLの機能デモ
-- PGの1つのデータベースが複数のツールを置き換えられる理由を示す
-- ============================================

-- 1. ACIDトランザクション(アプリケーション層の整合性処理が不要)
BEGIN;
UPDATE accounts SET balance = balance - 100 WHERE user_id = 1;
UPDATE accounts SET balance = balance + 100 WHERE user_id = 2;
COMMIT;

-- 2. JSONBストレージ(MongoDB不要)
INSERT INTO products (name, attributes)
VALUES ('スマートウォッチ', '{"color": "black", "battery_life_hours": 48, "waterproof": true}'::jsonb);

-- 3. 全文検索(Elasticsearch不要)
SELECT name, ts_rank(
    to_tsvector('english', name),
    plainto_tsquery('english', 'smart watch')
) AS relevance
FROM products
WHERE to_tsvector('english', name) @@ plainto_tsquery('english', 'smart watch')
ORDER BY relevance DESC;

-- 4. ウィンドウ関数(アプリケーション層のランキング処理が不要)
SELECT name, price,
    RANK() OVER (ORDER BY price DESC) AS price_rank
FROM products;

-- 5. UPSERT(アプリケーション層の競合処理が不要)
INSERT INTO products (name, price, attributes)
VALUES ('スマートウォッチ', 199.99, '{"color": "black", "battery_life_hours": 48}'::jsonb)
ON CONFLICT (name)
DO UPDATE SET price = EXCLUDED.price,
              attributes = EXCLUDED.attributes
RETURNING id, name, price;

Output(抜粋):

TEXT
 -- UPSERT RETURNING の出力:
 id |    name     | price
----+-------------+--------
  1 | スマートウォッチ | 199.99

❓ よくある質問

Q PostgreSQLは完全に無料ですか?隠れた商用ライセンスはありますか?
A PostgreSQLはPostgreSQLライセンス(BSDライク)を使用しているため、商用利用を含めて自由に使用、改変、配布できます。隠れた料金は一切ありません。MySQLのGPLよりも寛容で、アプリケーションコードをオープンソースにする必要さえありません。
Q PostgreSQLは小規模プロジェクトに適していますか?重すぎませんか?
A PostgreSQLの最小インストールは約50MBのメモリで動作します。小規模プロジェクトでは、PGのゼロコンフィグモードでそのまま使用できます。MySQLと比較して、PGのデフォルト設定は既に安全で信頼性があり、小規模プロジェクトでも「重すぎる」とは感じません。
Q PostgreSQLとMySQLのどちらを選ぶべきですか?
A プロジェクトが複雑なクエリ、JSONB、全文検索、GIS、高同時書き込みを必要とする場合はPostgreSQLを選んでください。プロジェクトがシンプルなCRUDで、チームがMySQLしか知らない場合や、最大の読み取りパフォーマンスが必要な場合はMySQLで十分です。2024年以降、新規プロジェクトでPostgreSQLを選ぶ割合は上昇し続けています。
Q MySQLからPostgreSQLへの移行は難しいですか?
A 中小規模のプロジェクトでは、移行に約1〜2週間かかります。作業のほとんどはSQL構文の違い(例:バッククォート→ダブルクォート、AUTO_INCREMENT→SERIAL/IDENTITY)です。ツールとしては、pgLoaderがデータとスキーマを自動的に移行できます。
Q PostgreSQLはMySQLより本当に速いですか?
A OLTP(単純な読み書き)シナリオでは、両者はほぼ同等です。高同時書き込み、複雑なJOIN、ウィンドウ関数、JSONBクエリでは、PostgreSQLがMySQLを明らかに上回ります。PGのMVCCは読み取りと書き込みが互いにブロックしないことが核心的な強みです。
Q PostgreSQLの前にMySQLを学ぶ必要がありますか?
A いいえ。PostgreSQLのSQLは標準SQLにより近いため、PGを先に学ぶ方がむしろ良いです。PGを理解すれば、MySQLは簡単に感じられます(PGがより標準的な構文を教えてくれるからです)。

📖 まとめ


📝 練習問題

  1. 基礎(★): MySQLと比較してPostgreSQLをユニークにしている3つの機能(MySQLにないか大幅に劣る機能)を挙げ、それぞれの利点を一文で説明してください。

  2. 中級(★★): コース情報(構造化)と学生のノート(非構造化)を保存し、コース内容を検索する必要があるオンライン教育プラットフォームのデータベースを選定するとします。PostgreSQLまたはMySQLを選ぶ理由を、少なくとも3つの技術的特徴を挙げて論じてください。

  3. 発展(★★★): PostgreSQLドキュメントの「Feature Matrix」ページ(「PostgreSQL Feature Matrix」で検索)を読み、このレッスンで触れられていないPGの機能を3つ見つけ、それぞれがどの外部ツールやミドルウェアを置き換えられるかを説明してください。

Web-Tutorial.com

Web-Tutorial 技術チーム

複数の開発者によって共同維持されているプログラミングチュートリアルプラットフォーム。各チュートリアルは専門分野の開発者が執筆・レビューしています。正確で信頼性の高いコンテンツを目指しています — 問題を見つけた場合はお知らせください。

100%