はじめに
「NoSQL」と一括りにされがちですが、その中身はKey-Value、ドキュメント、ワイドカラム、グラフ、ベクトル、時系列、検索エンジンと、性格の全く違うデータベースの寄せ集めです。
この記事は、それぞれのデータベースを「データの形」「得意な検索パターン」「クエリの書き方」の3点セットで一気に整理するチートシートです。実務でDBを選ぶときの「1枚目のマップ」として使えることを目指しました。
なお、この記事は「RDB以外」を扱いますが、多くのシステムでは今もRDBが本命です。「RDBが黙って守ってくれているものは何か」を掘り下げた記事も別途書いています。合わせてどうぞ。
0. 全体マップ
早見表
| 種類 | 代表エンジン | データの形 | 得意 | 苦手 |
|---|---|---|---|---|
| RDB | PostgreSQL / MySQL / Oracle / SQLite | 行と列のテーブル | 整合性・複雑なJOIN・トランザクション | 半構造データ・水平スケール |
| Key-Value型 | Redis / DynamoDB / Memcached / etcd | key → value | 超高速な単純検索・キャッシュ | 値の中身での検索 |
| ドキュメント型 | MongoDB / Firestore / Couchbase | JSON文書 | 柔軟なスキーマ・階層構造 | 複雑なJOIN・強い整合性 |
| ワイドカラム型 | Cassandra / HBase / ScyllaDB / Bigtable | 行キー+可変列 | 大量書き込み・線形スケール | 後付けの複雑な検索 |
| グラフ型 | Neo4j / Neptune / ArangoDB | ノードとエッジ | 多段階の関係探索 | 大量の一括集計 |
| ベクトル型 | Pinecone / Qdrant / Weaviate / pgvector | 埋め込みベクトル | 意味的な類似検索 | 完全一致・厳密な条件検索 |
| 時系列型 | InfluxDB / TimescaleDB / Prometheus | timestamp+値 | 連続データの蓄積と集約 | 更新・削除の多い用途 |
| 検索エンジン型 | Elasticsearch / OpenSearch / Meilisearch | 転置インデックス | 全文検索・あいまい検索 | トランザクション処理 |
1. Key-Value型(キーバリューストア)
データ構造イメージ
┌──────────────────┬───────────────────────────┐
│ KEY │ VALUE │
├──────────────────┼───────────────────────────┤
│ user:1001:name │ "Taro Yamada" │
│ session:ab12cd │ {token:..., exp:...} │ ← 中身はDB側は関知しない
│ page:home:views │ 48213 │
│ cart:u1001 │ ["item:22","item:87"] │
└──────────────────┴───────────────────────────┘
検索は「キー指定のみ」→ ハッシュ表と同じ O(1) 相当の速さ
アクセスの流れ(キャッシュとしての典型構成)
特徴
- キーと値のペアだけで管理する、最もシンプルな構造
- 多くはインメモリ動作で、ミリ秒未満の応答が可能
- 値の中身では検索できない(=「名前がTaroの人」は探せない)
相性の良い用途
- セッション情報、認証トークン
- DBの手前に置くキャッシュ
- ランキング・カウンター(いいね数、PV数)
- ショッピングカートのような一時的な状態
クエリ方法:コマンド(API)ベース
# Redis
SET user:1001:name "Taro Yamada" # キー user:1001:name に文字列を保存
GET user:1001:name # キーを指定して値を取得
INCR page:home:views # このキーの数値を +1(アトミック演算)
EXPIRE session:ab12cd 3600 # 3600秒後に自動削除(TTL指定)
# --- Sorted Set:スコア付きでメンバーを保存し、スコア順に自動で並ぶ特殊な型 ---
ZADD ranking 1500 "player:A" # スコア1500で player:A を登録
ZADD ranking 2100 "player:B" # スコアの高い順に内部で自動整列
ZREVRANGE ranking 0 9 # 上位10件を取得
2. ドキュメント型データベース
RDBとの構造比較
ドキュメントごとにフィールドが違ってよい
コレクション "products"
┌─────────────────────────────┐ ┌─────────────────────────────┐
│ _id: "p001" │ │ _id: "p002" │
│ name: "小説A" │ │ name: "ノートPC" │
│ author: "山田" │ │ cpu: "Core i7" │ ← 項目が
│ pages: 320 │ │ memory_gb: 16 │ 全然違う
│ │ │ ports: ["USB-C","HDMI"] │
└─────────────────────────────┘ └─────────────────────────────┘
同じコレクションに同居できる(スキーマレス)
特徴
- JSON(BSON)に近い「ドキュメント」単位で保存
- スキーマが緩やかで、フィールドの追加・省略が自由
- ネスト構造をそのまま1レコードとして扱えるためJOINが減る
- シャーディングによる水平分散が前提の製品が多い
相性の良い用途
- 商品カタログ(商品ごとに項目数が違う)
- CMS、ブログ記事、ユーザープロフィール
- Web/モバイルアプリのバックエンド(フロントのJSONとほぼ1対1)
- スキーマが頻繁に変わる初期フェーズのプロダクト
クエリ方法:JSONライクなクエリ言語
// 検索:SQLの WHERE に相当
db.products.find({ category: "book", price: { $lt: 2000 } })
// 更新
db.products.updateOne({ _id: "p001" }, { $set: { stock: 15 } })
// 集計パイプライン:SQLの GROUP BY に相当
db.orders.aggregate([
{ $match: { status: "completed" } },
{ $group: { _id: "$customerId", total: { $sum: "$amount" } } },
{ $sort: { total: -1 } }
])
3. ワイドカラム型(列指向分散DB)
データ構造イメージ
RowKey │ 列は「行ごとに」違ってよい(数千〜数百万列も可)
─────────────┼──────────────────────────────────────────────
user:001 │ name:太郎 │ age:28 │
user:002 │ name:花子 │ email:x@y.z │ tel:090-xxxx │ city:千葉
sensor:t01 │ 2026-07-01T00:00:Z=21.3 │ 00:01:Z=21.5 │ 00:02:Z=21.4 ...
↑ タイムスタンプそのものが列名になる設計もよく使う
Key-Value型・ドキュメント型との違い
一言で言うと、「Key-Valueに、DBが理解できる列構造をつけて、超巨大にスケールできるようにしたもの」 がワイドカラム型です。
| 観点 | Key-Value型 | ドキュメント型 | ワイドカラム型 |
|---|---|---|---|
| キーで引ける単位 | 1つの値(ブロブ) | 1つのJSON文書 | 1つの行(=複数の名前付き列の集合) |
| DBは値の中身を理解しているか | しない(不透明なバイト列) | JSON構造を理解 | 列の名前と型を理解 |
| 「1レコード内の一部だけ」を読める | 不可(値まるごと取得) | 部分投影は可能 | 特定の列だけ読める(列指向の恩恵) |
| スキーマ | なし | 緩い(文書ごとに違ってOK) | 緩い(行ごとに違う列を持ってOK、ただし列は事前定義) |
| ネスト構造 | 値の中に任意に埋められる(DBは解釈しない) | 得意(深い階層OK) | 苦手(基本フラットな行×列) |
| 主な使いどころ | キャッシュ・セッション | Web/モバイルのメイン格納 | 超大量書き込み・時系列・イベントログ |
| データ量の想定 | 数GB〜数TB | 〜数TB | 数十TB〜PB級(数百ノードで水平分散) |
| クエリの自由度 | キー完全一致のみ | 値の中身で柔軟に検索できる | 事前に決めたパターンでしか引けない(クエリファースト設計) |
イメージで捉えるなら:
- Key-Valueは「巨大なハッシュ表」→ とにかく速いが、値の中身は問わない
- ドキュメントは「JSONの倉庫」→ 値の中身で柔軟に検索できる
- ワイドカラムは「果てしなく横に広い、超巨大なExcel」→ 行ごとに列は違ってよく、書き込み量とデータサイズが桁違い(PB級)
分散のイメージ
ワイドカラム型の最大の武器は「ノードを追加するだけで性能が線形に伸びる」水平スケーラビリティです。
図の読み方:
-
RowKey(例:
user:001)= 1行を一意に識別するキー。RDBの主キーに相当 - ハッシュ関数 = RowKeyを 0.00〜1.00 の数値に変換する関数(同じキーは必ず同じ数値になる)
- 各ノードは「担当するハッシュ範囲」を持ち、その範囲に落ちる行だけを保存
- ノードを追加すると担当範囲が細分化され、既存データの一部だけが移動する → 無停止で線形にスケール
特徴
- 「行キー+列ファミリー」構造で、行ごとに異なる列を持てる
- 大量の書き込みと、ノード追加による線形スケールアウトに強い
- 一般に強整合性より可用性を優先(結果整合性)
- クエリファースト設計: 「どう読み出すか」を先に決めてテーブルを作る(後から自由な条件検索はできない)
相性の良い用途
- IoTセンサーデータ、大量のログデータ
- メッセージングアプリの履歴
- レコメンド用の行動ログ
- 巨大なイベントストリーム
クエリ方法: CQL(SQL風だがJOINなし)
CREATE TABLE sensor_data (
sensor_id text,
event_time timestamp,
value double,
PRIMARY KEY (sensor_id, event_time) -- ← 検索パターンをここで固定する
);
SELECT * FROM sensor_data
WHERE sensor_id = 'temp-01'
AND event_time > '2026-07-01';
WHERE value > 30のようなパーティションキー外の条件は原則NG。必要なら別テーブルを作る。
4. グラフデータベース
データ構造イメージ
上図で「田中さんにおすすめの商品」を考えると、田中 → 佐藤(友人)→ 商品B という2ホップの経路が一瞬でたどれます。
RDBとの決定的な違い
■ RDB で「友達の友達の友達」を探す
users ⋈ friends ⋈ friends ⋈ friends ← JOINが3段
段数が増えるほど、探索対象が指数的に膨らんで急激に遅くなる
1段: ▓▓ 速い
2段: ▓▓▓▓▓▓▓▓ やや遅い
3段: ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ かなり遅い
■ グラフDB(インデックスフリー隣接)
各ノードが「隣のノードへのポインタ」を直接持つ
→ 1ホップ進むコストがほぼ一定
1段: ▓▓
2段: ▓▓▓
3段: ▓▓▓▓ 段数が増えてもほぼ線形
補足: インデックスフリー隣接(Index-Free Adjacency)
グラフDBが「関係の探索」で速い理由の核心です。
RDBで「田中さんの友達」を探す場合:
1. usersテーブルから「田中」の id を探す ← インデックスを引く(O(log n))
2. friendsテーブルで user_id = 田中のid の行を探す ← インデックスを引く(O(log n))
3. さらに usersテーブルで friend_id を引き直す ← インデックスを引く(O(log n))
1ホップ進むたびに 「インデックスを引く」コスト(対数時間 O(log n)) がかかります。データが増えるほどインデックス自体も肥大化して遅くなります。
グラフDBの場合:
[田中さんノード]
│ ← このノード自身に「隣接ノードへの物理ポインタ(リスト)」が
▼ 直接くっついている(=インデックスを介さない)
┌─ 友達ポインタ ──> [佐藤さんノード]
├─ 友達ポインタ ──> [吉田さんノード]
└─ 購入ポインタ ──> [商品Aノード]
各ノードのレコード内に「隣のノードがディスク上のどこにあるか」を示すポインタが直に埋め込まれているため、次のノードへ進むコストは常に一定(O(1))。何段辿ってもインデックス検索は発生しません。
これが「インデックスを引かずに(=フリーに)隣(Adjacency)へ行ける」= インデックスフリー隣接。グラフDBが多段の関係探索でRDBに圧勝する根本原因は、この物理レイアウトの違いにあります。
なお、RDBのインデックスがなぜ「引くたびに O(log n)」になるのかは、B-treeの内部構造を可視化した別記事で扱っています。
RDBインデックスの動く図解 (B-tree / ハッシュ / 複合 / カバリング)
相性の良い用途
- SNSの友人・フォロー関係
- レコメンドエンジン(多段階の「買った人はこれも」)
- 不正検知(送金ネットワークの怪しいつながり)
- 組織図、サプライチェーン、知識グラフ
クエリ方法: Cypher(図をそのまま書くような構文)
// 「田中さんの友達の友達」
MATCH (me:Person {name: "田中"})-[:FRIEND]->(:Person)-[:FRIEND]->(fof:Person)
WHERE fof <> me
RETURN DISTINCT fof.name
構文の読み方:
(me:Person) -[:FRIEND]-> (fof:Person)
↑ノード ↑エッジ ↑ノード
()が丸いノード、-[]->が矢印つきエッジ。図の見た目とほぼ同じ。
// レコメンド: 友人が買っていて自分が買っていない商品
MATCH (me:Person {name:"田中"})-[:FRIEND]->(f)-[:PURCHASED]->(p:Product)
WHERE NOT (me)-[:PURCHASED]->(p)
RETURN p.name, count(*) AS score ORDER BY score DESC
他に Gremlin、SPARQL(RDF向け)といったクエリ言語もあります。
5. ベクトルデータベース
データ構造イメージ
テキスト・画像 ──[埋め込みモデル]──> ベクトル(数百〜数千次元の数値配列)
"犬がボールで遊んでいる" → [0.21, -0.88, 0.05, ... , 0.42] (1536次元)
"子犬がおもちゃで遊ぶ" → [0.19, -0.85, 0.07, ... , 0.40] ← 数値が近い!
"四半期の決算報告" → [-0.72, 0.31, 0.90, ... ,-0.11] ← 全然違う
検索の考え方(ベクトル空間を2次元に投影したイメージ)
▲
│ ● 子犬 意味が近いものは
│ ● 犬 空間上でも近くに集まる
│ ★ ←── クエリ「わんこ」
│ ● 柴犬
│
│ ● 決算
│ ● 売上高
│ ● 損益計算書
└──────────────────────────────────────▶
★から距離が近い順に top_k 件を返す = 類似検索
距離の測り方: コサイン類似度 / 内積 / ユークリッド距離
RAG(LLMの知識検索)での使われ方
特徴
- テキスト・画像・音声を埋め込みベクトルに変換して保存
- 完全一致ではなく「意味的に近いもの」を探す近似最近傍探索(ANN)
- HNSW / IVF などのインデックスにより、数百万〜数十億件からミリ秒〜数十msで検索
- メタデータフィルタ(例: カテゴリ=家電のものだけ)と組み合わせ可能
相性の良い用途
- LLMのRAG基盤(社内文書検索、FAQ、マニュアル検索)
- 画像・音声の類似検索
- レコメンド(ユーザー・商品の埋め込み類似度)
- セマンティック検索(キーワードが一致しなくても意味で探す)
- 異常検知(正常データの分布から離れたベクトルを検出)
クエリ方法
# Pinecone(専用API型)
results = index.query(
vector=query_embedding, # 質問を埋め込んだベクトル
top_k=5,
filter={"category": "manual"}, # メタデータで絞り込み
include_metadata=True
)
-- pgvector(PostgreSQL拡張型): SQLの中でベクトル検索できる
--
-- ▼ <=> について
-- <=> は pgvector が追加した「2つのベクトル間のコサイン距離」を計算する演算子。
-- ・返り値: 0 〜 2 の数値
-- 0 → 完全に一致(=意味がそっくり)
-- 1 → 直交(=無関係)
-- 2 → 真逆
-- ・値が小さいほど「意味的に近い」と解釈する
--
-- 他の距離演算子:
-- <-> ユークリッド距離
-- <#> 内積のマイナス(大きい類似度ほど小さい値にするため)
SELECT id, content,
embedding <=> '[0.12, 0.98, ...]' AS distance
FROM documents
WHERE category = 'manual' -- 通常のSQL条件と併用できるのが強み
ORDER BY embedding <=> '[0.12, 0.98, ...]'
LIMIT 5;
6. 時系列データベース
データ構造イメージ
CPU使用率(%)
100 │
│ ╭╮
75 │ ╭─╮ ╭╯╰╮
50 │ ╭────╯ ╰──╯ ╰──╮ ╭────
25 │╭──╯ ╰──────╯
0 └──────────────────────────────────▶ time
00:00 06:00 12:00 18:00
保存されるのは「timestamp + tag + value」の連続レコード
┌────────────────────┬───────────┬───────┐
│ time │ host │ value │
├────────────────────┼───────────┼───────┤
│ 2026-07-27T09:00:00│ web-01 │ 42.1 │
│ 2026-07-27T09:00:10│ web-01 │ 44.8 │ ← 追記のみ、更新しない
│ 2026-07-27T09:00:20│ web-01 │ 43.2 │
└────────────────────┴───────────┴───────┘
データのライフサイクル
特徴
- 「タイムスタンプ+値」に特化、データは基本的に追記のみ
- 自動的なダウンサンプリングと保持期間ポリシーを標準搭載
- 圧縮効率が高く、大量の連続データを低コストで長期保存できる
相性の良い用途
- サーバー監視メトリクス(CPU、メモリ、レスポンスタイム)
- IoTセンサー値(温度、湿度、位置情報)
- 株価・為替のティックデータ
- アプリケーションパフォーマンス監視(APM)
クエリ方法
-- TimescaleDB(PostgreSQL拡張): SQLがそのまま使える
SELECT time_bucket('1 hour', event_time) AS bucket,
avg(cpu_usage), max(cpu_usage)
FROM metrics
WHERE event_time > now() - interval '1 day'
GROUP BY bucket
ORDER BY bucket;
# Prometheus PromQL: 関数型のクエリ言語
rate(http_requests_total[5m]) # 5分間の増加率
avg_over_time(cpu_usage{host="web-01"}[1h]) # 1時間平均
7. 検索エンジン型データベース
転置インデックスのしくみ
■ 元の文書
doc1: "軽量なノートパソコンが欲しい"
doc2: "ノートに書く"
doc3: "パソコンの修理"
■ 形態素解析して転置インデックスを作る(単語 → 文書リスト)
┌────────────┬──────────────────┐
│ 単語 │ 出現する文書 │
├────────────┼──────────────────┤
│ 軽量 │ doc1 │
│ ノート │ doc1, doc2 │
│ パソコン │ doc1, doc3 │
│ 修理 │ doc3 │
└────────────┴──────────────────┘
■ 「ノートパソコン」で検索
ノート → {doc1, doc2}
パソコン → {doc1, doc3}
両方含む doc1 のスコアが最も高くなる → 関連度順に返却
検索リクエストの流れ
特徴
- 転置インデックスにより全文検索に特化
- 表記ゆれ、あいまい検索、関連度スコアリング、ファセット集計が得意
- ログの集約・可視化基盤としても広く使われる(Kibana等と併用)
相性の良い用途
- ECサイトの商品検索(あいまい検索・関連度順表示)
- ログ分析基盤
- ドキュメント検索、サポートFAQ検索
クエリ方法: JSON形式のクエリDSL
{
"query": {
"bool": {
"must": { "match": { "title": "ノートパソコン" } },
"filter": { "range": { "price": { "lte": 100000 } } }
}
},
"aggs": {
"by_brand": { "terms": { "field": "brand" } }
}
}
8. 選定フローチャート
9. 実務では「組み合わせる」のが普通
1つに絞らず複数のDBを併用する設計を Polyglot Persistence(多言語永続化) と呼びます。以下は社内ドキュメント検索を含むWebサービスの典型構成です。
併用時の注意点
| 論点 | 内容 |
|---|---|
| Source of Truth | 「正となるデータ」はどれか1つに決める。上図ではPostgreSQL |
| 同期のラグ | 検索用インデックスは通常あとから追いつく。即時反映が必要かを確認する |
| 運用コスト | DBが増えるほど監視・バックアップ・障害対応の対象が増える |
| まず1つで試す | 小規模なら pgvector や PostgreSQLの全文検索で足りることも多い |
まとめ
- RDBは万能だが、データの「形」とアクセスパターンによっては非RDBが桁違いに効率的
- 特に近年は、LLM活用に伴う ベクトルDB と、関係性の分析を担う グラフDB の重要性が上がっている
- 選定は「速いDBはどれか」ではなく「自分のデータの形に合った構造はどれか」で考える
- 実務では単一DBに絞らず、役割ごとに使い分けるのが一般的
そして最後に強調しておきたいのは、この記事で並べた7種類の非RDBがいくら強力でも、「正となるデータの置き場所(Source of Truth)」は今もほとんどの場合RDBだという事実です。上のPolyglot構成図でも、PostgreSQLだけが太枠で囲まれています。ワイドカラム型は結果整合性、Redisは揮発、ドキュメント型はトランザクション制約が弱い──それぞれ「速さ」や「柔軟さ」の裏で、RDBが黙って守ってくれている何かを手放しています。
「その手放しているものが具体的に何なのか」を、Excelで壊れる7つの事例から掘り下げた記事もあります。
もっと詳しく:
- もしもこの世界にRDBがなかったら (原子性・同時実行・一意性・参照整合性・永続性)
- RDBインデックスの動く図解 (B-tree / ハッシュ / 複合 / カバリング)
- 変なER図。あなたには、このER図の異常さがわかりますか?
バグ・ご意見は X @taitech_dev まで。