データベース基礎講座:RDB vs NoSQL、適材適所の選択法

DB-Enginesのランキングを見ると、トップ10のうち半数以上はいまもRDBMS(リレーショナルデータベース管理システム)が占めています¹。一方で、ドキュメント指向やKey-ValueなどのNoSQLデータベースも上位に定着し、Stack Overflow Developer SurveyでもPostgreSQLやMySQLと並んでMongoDBが大きな存在感を示します²。エンタープライズの主要トランザクションは長らくRDBが担ってきましたが³、イベントストリーミングや巨大ログ、パーソナライズのリアルタイム推論といった高スループット・大規模データの領域ではNoSQLの採用が広がっています⁴。実務の大規模プロダクトでは、RDBかNoSQLの二者択一ではなく、ユースケースごとに複数のデータストアを併用する設計(ポリグロット永続化)が成果につながる、という傾向が広く観察されます。対立ではなく適材適所に踏み込むほど選択肢は増えますが、判断軸を明確にすれば迷いは減ります。ここでは、RDB vs NoSQLの比較を実務者視点で再現可能にするために、ACIDとCAP、スキーマとクエリ、スケーリングとコストという軸で、選定と運用の勘所を整理します。
市場データと原理原則で押さえるRDB/NoSQLの立ち位置
RDBは行指向のテーブル、厳格なスキーマ、参照整合性、そしてトランザクションにおけるACID特性(原子性・一貫性・分離性・永続性)を中心に設計されています⁴。NoSQLはモデルの自由度や水平スケーリングの容易さを前面に出し、ドキュメント、ワイドカラム、Key-Value、グラフなどのバリエーションを持ちます。一般的な運用実態として、RDBは複雑結合や強い整合性が求められる業務に強く、NoSQLは超大規模スループットとスキーマ進化の速さで差別化します。選択を誤らないためには、抽象論から入るよりも、まず想定ワークロード(読み取り中心か書き込み中心か、レイテンシ目標、データ量、整合性要件)を具体化し、その要件を原理原則に写像する態度が有効です。
原理としてまずACIDとBASEのトレードオフを自覚します⁴。ACIDは金融や在庫など「整合性が価値そのものに直結」する場面で威力を発揮します。対してBASE(Basically Available, Soft state, Eventual consistency)は可用性と拡張性を優先し、最終的整合(遅れて一致する整合性)を受け入れます⁴。CAP定理は、ネットワーク分断(Partition)時に一貫性(Consistency)か可用性(Availability)のいずれかを必ず犠牲にするという制約を示します⁵。現実の製品は三択ではなく多くのチューニングパラメータで挙動を調整できます。したがって「RDBだからC、NoSQLだからA」と単純化せず、プロダクトの要件と運用設定(レプリケーション、整合性レベル、フェイルオーバー方針)を含めて議論すべきです。
スキーマ設計とクエリの自由度をどう天秤にかけるか
アプリケーションが進化するほどスキーマは変化します。RDBでは正規化を軸に冗長性を抑え、JOINで表現力を確保します。NoSQL、とくにドキュメント指向では「読み取りの形」に合わせてデータを事前に重複配置し、JOINを読み取り時ではなく書き込み時に肩代わりさせます。前者はクエリの柔軟さ、後者は読み取りの高速化とスケールで応えます。端的に言えば、RDBは「あとから多様な問いを投げる」ことに強く、NoSQLは「決まった問いをひたすら速く返す」ことに強い。後戻りコストは、RDBがスキーマ変更やマイグレーションの整備、NoSQLがアクセスパターンの固定化や重複更新の整合で支払うことになります。
性能SLOの言語化が最初の分岐点になる
選定の前にSLO(Service Level Objective:提供品質の目標)を具体的に言語化します。例えば、検索画面の読み取りはp95(遅い方から5%目の値)で50ms以内、書き込みはp95で200ms以内、同時接続は1,000、ピークQPSは3,000、ホットシャード(特定パーティションへの負荷集中)は避けたい、などの事実に落とすと、必要なデータ配置とインデックス、キャッシュ戦略が見えてきます。RDBであればセカンダリインデックスやカバリングインデックス(インデックスだけで必要列が揃う)、実行計画の安定化が鍵となり、NoSQLであればパーティションキーの選定とアクセスパターンの合致が支配的です。
比較の核心:ACID/CAP、スケーリング、コストの三点
ACIDの徹底度は監査要件と相関します。銀行口座の残高更新や在庫引当の二重消し込みなどは、直列化や少なくともREPEATABLE READ相当の隔離レベルが求められます。RDBはここで豊富な運用知見を持ちます。対して、SNSのフィードやレコメンドのビュー数カウントなどは、最終的整合が守られれば体験上の問題が生じにくく、NoSQLやキャッシュレイヤの一貫性モデルでも価値は毀損しません⁴。CAPの観点では、グローバル分散が要求されると遅延が跳ね上がるため、ユーザ局所性やライトの局所化、整合性レベルの調整(リージョン内は強、跨ぐと弱など)が実務的な解になります⁵。
スケーリングは垂直か水平かの話に見えますが、実態はデータ配置の設計に尽きます。RDBもシャーディングや読み取りレプリカで水平拡張できますが、アプリケーションがシャードキーを理解し、トランザクション範囲を単一シャードに収める設計が必要です。NoSQLは製品レベルでパーティション分散を前提化し、ホットパーティションの回避やキー空間の均等化に多くの知見が蓄積しています。どちらを選んでも、アクセスパターンが偏っていれば性能は頭打ちになります。
費用はストレージ、IOPS、ネットワーク、計算、そして運用の人的コストに分解して見積もると差が見えてきます。同じQPSを達成するにも、RDBは強い一貫性維持のために高性能ストレージとメモリを厚く積む傾向があり、NoSQLはパーティションを増やしてスループットを稼ぎ、ネットワークやノード数が増える方向に振れます。マネージドサービスではスケールユニットの刻みや課金単位(I/Oベース、プロビジョンドスループット、ストレージ消費など)に個性があるため、使用カーブに合わせた運用計画を選ぶのが賢明です。
RDBの実装イメージ:スキーマ厳格性とトランザクション制御
-- PostgreSQL: 在庫と受注の最小トランザクション例
BEGIN;
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;
UPDATE inventory
SET quantity = quantity - 1
WHERE sku = $1 AND quantity > 0;
INSERT INTO orders(order_id, sku, user_id, status)
VALUES ($2, $1, $3, 'CREATED');
COMMIT;
在庫引当のような整合性重視の処理では、隔離レベルを明示し、失敗時のロールバック戦略を合わせて設計します。実行計画の安定化には統計情報の更新とパラメータ化クエリが有効です。
-- 読み取り最適化のためのカバリングインデックス
CREATE INDEX idx_orders_user_status_created_at
ON orders(user_id, status, created_at) INCLUDE (total_amount);
-- 典型的なクエリはインデックスだけで解決される
SELECT order_id, created_at, total_amount
FROM orders
WHERE user_id = $1 AND status = 'CREATED'
ORDER BY created_at DESC
LIMIT 20;
読み取りのp95を短縮するには、必要な列をINCLUDEで取り込み、テーブルアクセスを避ける設計が功を奏します。
ドキュメント指向NoSQLの実装イメージ:アクセスパターン先行のモデリング
// MongoDB: ユーザの最近の注文を読み取りに最適化した設計
// 1ユーザ=1ドキュメントに最新20件を埋め込む(整合性要件に応じて分離も検討)
{
_id: ObjectId("..."),
userId: "u_123",
recentOrders: [
{ orderId: "o_987", total: 4200, createdAt: ISODate("2025-08-25T12:34:56Z") },
...
],
updatedAt: ISODate("2025-08-25T12:35:01Z")
}
// インデックスはアクセスに合わせて設計
// userIdでのポイント読み取りと、保持期間に応じたTTL/アーカイブを併用
db.user_orders.createIndex({ userId: 1 });
読み取りをO(1)に寄せるために埋め込みを選ぶと、書き込み時に並行更新の競合を考慮する必要が出てきます。アプリ側でのリトライと冪等性キー(同一操作の重複を防ぐ識別子)の導入が安定運用の鍵になります。
ワイドカラム系でのタイムシリーズ:書き込み最適とクエリの一貫性
-- Apache Cassandra: デバイスのメトリクスを日単位でパーティション
CREATE TABLE device_metrics (
device_id text,
day date,
ts timestamp,
metric map<text, double>,
PRIMARY KEY ((device_id, day), ts)
) WITH CLUSTERING ORDER BY (ts DESC);
-- 1日の範囲クエリを想定した読み取り
SELECT ts, metric FROM device_metrics
WHERE device_id = 'd-1' AND day = '2025-08-25'
AND ts >= '2025-08-25T00:00:00Z' AND ts < '2025-08-26T00:00:00Z'
LIMIT 1000;
ホットパーティションを避けるために日やハッシュを併用し、ライトの局所性を保ちます。Consistency Level(読み書き時の整合性の強さ)の選択で、可用性と整合性の現実的な落とし所を決めます。
ユースケース別の適材適所:判断を再現可能にする
コア台帳やマルチエンティティの業務レポートのように結合とトランザクションの価値が高い場面はRDBが主役になります。スキーマの厳格さは監査や変更履歴の明瞭さに直結し、まさに機能そのものです。可視化に必要な集計や検索の高速化はマテリアライズドビュー、列指向の補助ストア、あるいは検索エンジンとの連携で補完できます。NoSQL的なビューはRDBの外側に置き、単一の真実の出どころ(Single Source of Truth)をRDBに戻す設計が管理しやすいでしょう。
一方で、パーソナライズ、セッション、クリックログ、IoTテレメトリなどの膨張するイベントストリームは、NoSQLの出番が増えます。ドキュメント指向は多様な属性を素早く取り込み、スキーマ進化をアプリ側のバージョニングで吸収できます。ワイドカラムは巨大な時間系列に適し、古いデータの階層化やTTLで保管コストを抑えられます。グラフデータベースはソーシャルやレコメンドの関係探索に有効で、RDBで実現しようとすると結局はアプリでグラフを再実装することになりがちです。
検索や推薦の体験を最大化したい場合、トランザクションの書き込みパスとユーザ向け読み取りパスを意図的に分離する手が有効です。Write-optimizedなストアにまず確実に記録し、取り回しの良い形に変換してRead-optimizedなストアへ投影します。いわゆるCQRS(Command Query Responsibility Segregation)+イベント駆動の考え方で、RDBとNoSQLを補完的に並べます。このアプローチは待ち時間の二重管理と遅延の説明が要るため、SLOとUXのすり合わせが欠かせません。
読み取りは速いが整合が弱いときの落としどころ
最終的整合を許容する代わりに、ユーザ体験上の違和感を減らす工夫を加えます。例えば、注文履歴の最新一件は直書き込みストアから同期読み取りし、それ以外は投影ストアから返すハイブリッド戦略が有効です。UIには同期中の意味合いを伝えるプレースホルダを出し、整合遅延の存在を曖昧にしないことが信頼につながります。
アドホック分析の需要が強いときの選択
未知の切り口でデータを切る要件が多い場合、表現力と結合力が必要です。RDBやデータウェアハウスが基盤となり、NoSQLの生データは前処理の中継点に止めます。スキーマオンリード(読み出し時にスキーマを当てる手法)は柔軟さの裏で集計の一貫性と再現性を損ねやすいため、ビジネス定義のディクショナリ化と検算の自動化をセットにするのが安全です。
導入と運用の現実:SLO、コスト、ガバナンス
導入期間の目安を言語化すると意思決定が加速します。RDB中心で既存資産がある場合、スキーマ駆動の開発フローにモックと自動マイグレーションを組み込み、小〜中規模なら2〜4週間で初期版を立ち上げるのが一つの目安になります。NoSQL中心の場合はアクセスパターンからモデリングし、イベントスキーマのバージョニング規約と冪等性の合意を先に固めます。どちらでも、CIでスキーマ互換性を検証し、負荷テストでp95/p99の指標を計測しておくと後戻りが減ります。
SLOはユーザ中心の指標に落とし込むのが肝要です。たとえば、商品詳細ページの読み取りはキャッシュヒット時p95で20ms、ミス時でも70ms以内、在庫引当の書き込みは200ms以内で、決済の二重実行は0件、という品質表現が適切です。これに合わせてDBの整合性レベル、インデックス、キャッシュのTTL、キューの再試行回数を調整します。SLO未達のときにDBだけを責めないためにも、アプリ、ネットワーク、キャッシュ、検索エンジンを含めたE2Eの計測体制を整えます。
費用対効果では、読み取り多めのワークロードならキャッシュと読み取りレプリカの組み合わせが効率的で、書き込み多めならバッチ集約と非同期化で突発のピークを平らにします。RDBであればホットテーブルの分割、NoSQLであればパーティションキーの見直しでスケール単価を抑えられます。マルチテナントではテナント分離の粒度を検討し、RDBはスキーマ分離かデータベース分離、NoSQLはパーティションキーにテナントIDを含める戦略が実務的です。
// Go: p95観測を意識した読み取りの雛形(PostgreSQL)
package main
import (
"context"
"database/sql"
"log"
"time"
_ "github.com/lib/pq"
)
func main() {
db, err := sql.Open("postgres", "postgres://user:pass@localhost:5432/app?sslmode=disable")
if err != nil { log.Fatal(err) }
defer db.Close()
ctx, cancel := context.WithTimeout(context.Background(), 80*time.Millisecond)
defer cancel()
stmt, err := db.PrepareContext(ctx, `SELECT order_id, total_amount FROM orders WHERE user_id=$1 ORDER BY created_at DESC LIMIT 20`)
if err != nil { log.Fatal(err) }
defer stmt.Close()
rows, err := stmt.QueryContext(ctx, "u_123")
if err != nil { log.Fatal(err) }
defer rows.Close()
for rows.Next() { var id string; var total int; _ = rows.Scan(&id, &total) }
}
アプリ側で明確なタイムアウトを設定し、SLOを破るクエリを早期に遮断するのは、下層のスローダウンをユーザ体験に伝播させない基本策です。レイテンシバジェット(リクエスト全体に割り当てる遅延の持ち時間)の観点で、DBに割ける時間配分をあらかじめ決めます。
移行とハイブリッド:段階的な勝ち筋を作る
既存RDBからNoSQLへ、あるいはその逆の移行は、いきなり全テーブル・全コレクションを動かすと失敗確率が上がります。まずは読み取り負荷の高いビューだけを複製し、イベント駆動で同期します。書き込み経路の切り替えは、冪等IDと二重書き込み期間を設け、差分検証ができる状態で進めます。機能フラグでトラフィックを段階的に流し、SLOとエラーレートを監視しながら、フェーズごとにロールバックパスを確保します。過信せず観測し、観測に基づいて次の一手を決める姿勢が結局の近道です。
まとめ:対立から統合へ、選択から設計へ
RDBとNoSQLはどちらが優れているかではなく、価値に最短で到達できる組み合わせをどう設計するかの問題です。ACIDとBASE、CAP定理、スキーマ設計とクエリ、水平スケーリングと費用曲線という複数の軸を、特定のワークロードとSLOに投影すると判断は揺らぎません。整合性が価値の中心にあるならRDBを核に置き、可用性とスループットが勝つならNoSQLを前に出す。そして多くの現場では、その両方を同じプロダクトの中で並走させます。
次のスプリントでできる小さな一歩として、主要エンドポイントのSLOを文章で定義し、現在のデータアクセスを実測してみてください。数値が言葉を支え、言葉が設計を導き、設計が選択を楽にします。チームで共通言語を持つところから始めましょう。
参考文献
- DB-Engines. DB-Engines Ranking – popularity ranking of database management systems. https://db-engines.com/en/ranking
- Stack Overflow. Stack Overflow Developer Survey 2023. https://survey.stackoverflow.co/2023/
- NTT東日本. RDB(リレーショナルデータベース)とは/NoSQLとの違い. https://business.ntt-east.co.jp/content/cloudsolution/column-338.html
- Amazon Web Services. What’s the Difference Between an ACID and a BASE Database? https://aws.amazon.com/compare/the-difference-between-acid-and-base-database/
- ScyllaDB Glossary. CAP Theorem. https://www.scylladb.com/glossary/cap-theorem/