SQL과 NoSQL 데이터베이스 간의 선택은 가장 중요한 아키텍처 결정 중 하나입니다.
개요
근본적인 차이는 데이터 구성과 쿼리 방법에 있습니다.
NoSQL 데이터베이스 유형
NoSQL은 단일 기술이 아닌 다양한 데이터 모델의 데이터베이스 패밀리입니다.
NoSQL Database Types:
1. Document Databases (MongoDB, CouchDB, Firestore)
- Store data as JSON/BSON documents
- Flexible schema per document
- Good for: content management, catalogs, user profiles
- Example: { "name": "John", "orders": [...], "prefs": {...} }
2. Key-Value Stores (Redis, DynamoDB, Memcached)
- Simple key → value pairs
- Fastest reads/writes
- Good for: caching, sessions, leaderboards, counters
- Example: "user:123" → "{\"name\": \"John\"}"
3. Wide-Column Stores (Cassandra, ScyllaDB, HBase)
- Tables with rows and dynamic columns
- Optimized for writes and time-series data
- Good for: IoT, logging, metrics, messaging
- Example: row_key → {col1: val1, col2: val2, ...}
4. Graph Databases (Neo4j, ArangoDB, Amazon Neptune)
- Nodes and edges (relationships are first-class)
- Optimized for traversing relationships
- Good for: social networks, recommendations, fraud detection
- Example: (User)-[:FOLLOWS]->(User)SQL vs NoSQL 비교
| 항목 | SQL | NoSQL |
|---|---|---|
| 데이터 모델 | 테이블 (행과 열) | 문서, 키-값, 와이드 컬럼, 그래프 |
| 스키마 | 엄격함 | 유연함 |
| 쿼리 언어 | SQL (표준화) | DB별 고유 |
| 스케일링 | 수직 스케일링 | 수평 스케일링 |
| ACID 트랜잭션 | 완전 ACID | DB마다 다름 |
| JOIN | 완전 JOIN 지원 | 제한적 |
| 일관성 | 강한 일관성 | 최종 일관성 |
| 성능 | 복잡한 쿼리에 우수 | 대규모 단순 쿼리에 우수 |
| 최적 용도 | 구조화된 데이터, 복잡한 쿼리 | 유연한 데이터, 높은 쓰기 |
ACID vs BASE
SQL은 ACID 모델, NoSQL은 BASE 모델을 따릅니다.
ACID (SQL Databases):
A - Atomicity: All operations succeed or all fail (no partial updates)
C - Consistency: Data always moves from one valid state to another
I - Isolation: Concurrent transactions don't interfere with each other
D - Durability: Committed data survives system failures
BASE (Many NoSQL Databases):
BA - Basically Available: System guarantees availability (may serve stale data)
S - Soft state: State may change over time (even without input)
E - Eventual consistency: System will become consistent eventually
Practical Impact:
ACID: "Transfer $100 from Account A to Account B"
→ Both debit and credit happen, or neither does
→ No money is lost or created
→ Other transactions see either the before or after state
BASE: "Update user profile across 3 data centers"
→ All 3 data centers will eventually have the update
→ For a brief period, different data centers may show different data
→ Acceptable for social media posts, not for bank transfersSQL을 선택할 때
- 구조화된 관계형 데이터
- 복잡한 쿼리
- ACID 트랜잭션
NoSQL을 선택할 때
- 유연한 스키마
- 높은 쓰기 처리량
- 수평 스케일링
코드 예시
SQL (PostgreSQL)
-- PostgreSQL: Relational schema with strong typing
CREATE TABLE users (
id SERIAL PRIMARY KEY,
name VARCHAR(100) NOT NULL,
email VARCHAR(255) UNIQUE NOT NULL,
role VARCHAR(20) DEFAULT 'user',
created_at TIMESTAMPTZ DEFAULT NOW()
);
CREATE TABLE posts (
id SERIAL PRIMARY KEY,
user_id INTEGER REFERENCES users(id) ON DELETE CASCADE,
title VARCHAR(300) NOT NULL,
content TEXT NOT NULL,
tags TEXT[], -- PostgreSQL array type
metadata JSONB DEFAULT '{}', -- Flexible JSON column!
published BOOLEAN DEFAULT false,
created_at TIMESTAMPTZ DEFAULT NOW()
);
CREATE INDEX idx_posts_user ON posts(user_id);
CREATE INDEX idx_posts_tags ON posts USING GIN(tags);
CREATE INDEX idx_posts_metadata ON posts USING GIN(metadata);
-- Complex query: posts with author info and comment count
SELECT
p.title,
p.created_at,
u.name AS author,
COUNT(c.id) AS comment_count,
p.metadata->>'views' AS views
FROM posts p
JOIN users u ON p.user_id = u.id
LEFT JOIN comments c ON c.post_id = p.id
WHERE p.published = true
AND p.tags @> ARRAY['javascript']
GROUP BY p.id, u.name
ORDER BY p.created_at DESC
LIMIT 20;
-- ACID Transaction
BEGIN;
UPDATE accounts SET balance = balance - 100 WHERE id = 1;
UPDATE accounts SET balance = balance + 100 WHERE id = 2;
INSERT INTO transfers (from_id, to_id, amount) VALUES (1, 2, 100);
COMMIT;NoSQL (MongoDB)
// MongoDB: Document-based, flexible schema
// No schema definition needed — just insert documents
// Insert a user with embedded data
db.users.insertOne({
name: "Jane Smith",
email: "jane@example.com",
role: "admin",
profile: {
bio: "Full-stack developer",
skills: ["TypeScript", "React", "Node.js"],
social: {
twitter: "@janesmith",
github: "janesmith",
},
},
preferences: {
theme: "dark",
notifications: true,
},
createdAt: new Date(),
});
// Insert posts (embedded or referenced)
db.posts.insertOne({
userId: ObjectId("user123"),
title: "Getting Started with MongoDB",
content: "MongoDB stores data as documents...",
tags: ["mongodb", "database", "nosql"],
metadata: { views: 1523, likes: 42 },
comments: [
{ user: "Bob", text: "Great article!", date: new Date() },
{ user: "Alice", text: "Very helpful", date: new Date() },
],
published: true,
createdAt: new Date(),
});
// Query with aggregation pipeline
db.posts.aggregate([
{ $match: { published: true, tags: "javascript" } },
{ $lookup: {
from: "users",
localField: "userId",
foreignField: "_id",
as: "author"
}},
{ $unwind: "$author" },
{ $project: {
title: 1,
"author.name": 1,
commentCount: { $size: "$comments" },
views: "$metadata.views"
}},
{ $sort: { createdAt: -1 } },
{ $limit: 20 }
]);NoSQL (Redis)
# Redis: Key-Value store (in-memory, ultra-fast)
# Simple key-value
SET user:123:name "Jane Smith"
GET user:123:name # → "Jane Smith"
# Hash (object-like)
HSET user:123 name "Jane" email "jane@example.com" role "admin"
HGET user:123 name # → "Jane"
HGETALL user:123 # → all fields
# List (queue/stack)
LPUSH notifications:user:123 "New follower: Bob"
LPUSH notifications:user:123 "New comment on your post"
LRANGE notifications:user:123 0 9 # Get latest 10
# Set (unique values)
SADD post:456:likes "user:123" "user:456" "user:789"
SCARD post:456:likes # → 3 (count unique likes)
SISMEMBER post:456:likes "user:123" # → 1 (true)
# Sorted Set (leaderboard)
ZADD leaderboard 1500 "player:alice"
ZADD leaderboard 2200 "player:bob"
ZADD leaderboard 1800 "player:charlie"
ZREVRANGE leaderboard 0 9 WITHSCORES # Top 10 players
# TTL (auto-expiring keys — perfect for caching)
SET api:cache:/users "[\"data\"]" EX 300 # expires in 5 minutes
TTL api:cache:/users # → seconds remaining스케일링 전략
SQL 스케일링
SQL은 주로 수직 스케일링.
SQL Scaling Strategies:
1. Vertical Scaling (Scale Up)
├── More CPU cores
├── More RAM (buffer pool)
├── Faster SSD (NVMe)
└── Effective up to ~1TB RAM, 128 cores
2. Read Replicas (Horizontal Read Scaling)
Primary (writes) → Replica 1 (reads)
→ Replica 2 (reads)
→ Replica 3 (reads)
3. Connection Pooling (PgBouncer, ProxySQL)
App → Pooler → Database (reuse connections)
4. Partitioning (Table-level)
orders_2024, orders_2025, orders_2026
5. Sharding (Application-level)
Users A-M → Shard 1
Users N-Z → Shard 2
(Complex, usually avoid if possible)
6. Managed Services
- Supabase, Neon, PlanetScale (auto-scaling)
- AWS Aurora, Google Cloud SQLNoSQL 스케일링
NoSQL은 수평 스케일링을 위해 설계.
NoSQL Scaling (Built-in Horizontal):
MongoDB (Sharding):
Config Servers (metadata)
├── Shard 1: users with _id A-F
├── Shard 2: users with _id G-M
├── Shard 3: users with _id N-S
└── Shard 4: users with _id T-Z
Mongos Router → routes queries to correct shard
Redis (Cluster Mode):
├── Node 1: hash slots 0-5460
├── Node 2: hash slots 5461-10922
└── Node 3: hash slots 10923-16383
Each node has a replica for failover
Cassandra (Ring Architecture):
├── Node A: token range 0-25%
├── Node B: token range 25-50%
├── Node C: token range 50-75%
└── Node D: token range 75-100%
Replication factor: 3 (each row on 3 nodes)
Add nodes → data automatically rebalances인기 DB 비교
Database Type Best For License
---------------------------------------------------------------------------
PostgreSQL SQL General purpose, JSONB, analytics PostgreSQL (OSS)
MySQL SQL Web applications, WordPress GPL / Commercial
SQLite SQL Embedded, mobile, serverless Public Domain
MariaDB SQL MySQL drop-in replacement GPL
MongoDB Document Flexible schema, content mgmt SSPL
Redis Key-Value Caching, sessions, real-time BSD (+ commercial)
DynamoDB Key-Value AWS serverless, auto-scaling Proprietary
Cassandra Wide-Column Time-series, IoT, high write Apache 2.0
Neo4j Graph Social networks, recommendations GPL / Commercial
Elasticsearch Search Full-text search, logs, analytics SSPL / Apache 2.0
CockroachDB NewSQL Global SQL, horizontal scale BSL / Commercial
PlanetScale NewSQL Serverless MySQL (Vitess-based) Proprietary
TiDB NewSQL HTAP, MySQL compatible Apache 2.0
Supabase SQL (PG) Firebase alternative, PostgreSQL Apache 2.0마이그레이션 패턴
많은 애플리케이션이 SQL과 NoSQL 모두 사용합니다.
Polyglot Persistence Architecture:
┌─────────────────────┐
│ Application Layer │
└─────────┬───────────┘
│
┌───────────────────┼───────────────────┐
│ │ │
┌───────▼───────┐ ┌───────▼───────┐ ┌───────▼───────┐
│ PostgreSQL │ │ Redis │ │ MongoDB │
│ │ │ │ │ │
│ - Users │ │ - Sessions │ │ - CMS content │
│ - Orders │ │ - Cache │ │ - Product │
│ - Payments │ │ - Rate limits │ │ catalogs │
│ - Inventory │ │ - Leaderboard │ │ - User prefs │
│ - Reports │ │ - Pub/Sub │ │ - Event logs │
└───────────────┘ └───────────────┘ └───────────────┘
Transactions Performance Flexibility
Use each database for what it does best.자주 묻는 질문
SQL과 NoSQL을 함께 사용할 수 있나요?
네. 폴리글랏 퍼시스턴스라는 일반적인 패턴입니다.
NoSQL이 SQL보다 빠른가요?
쿼리 패턴에 따라 다릅니다.
스타트업은 SQL? NoSQL?
PostgreSQL로 시작하세요.
MongoDB는 프로덕션에 적합한가요?
네. 널리 사용됩니다.
NewSQL은?
SQL의 ACID와 NoSQL의 스케일링을 결합.
REST API에 최적의 DB는?
PostgreSQL이 가장 안전한 선택입니다.
관련 도구 및 가이드
- JSON Formatter - Format MongoDB documents and API responses
- SQL Formatter - Format and beautify SQL queries
- CSV to JSON Converter - Convert between data formats
- SQL Joins Visual Guide
- MongoDB vs PostgreSQL Detailed Comparison
- Prisma Schema Relations Guide
- REST API Design Guide