본문으로 건너뛰기

⚖️ SQL vs NoSQL

📖 정의

SQL(관계형 데이터베이스)은 테이블 형태로 정형화된 구조에 데이터를 저장하며, SQL 언어로 조작합니다. NoSQL(비관계형 데이터베이스)은 유연한 스키마로 다양한 형태의 데이터를 저장하며, 수평 확장에 유리합니다. 각각 장단점이 있어 프로젝트 요구사항에 따라 선택해야 합니다.

🎯 비유로 이해하기

도서관 vs 창고

SQL (관계형 DB) = 정리된 도서관
├─ 모든 책이 정해진 위치에 분류됨
├─ 도서 카드에 정확한 정보 기록
├─ 엄격한 대출/반납 규칙
└─ 찾기 쉽지만 유연성 낮음

NoSQL (비관계형 DB) = 유연한 창고
├─ 다양한 형태의 물건 보관 가능
├─ 빠르게 추가/제거 가능
├─ 공간 확장이 쉬움
└─ 유연하지만 정리가 어려울 수 있음

학교 출석부 vs 소셜미디어

SQL = 학교 출석부
학생 테이블:
┌────┬─────────┬─────┬────────┐
│ ID │ 이름 │나이 │ 반 │
├────┼─────────┼─────┼────────┤
│ 1 │ 김철수 │ 15 │ 1반 │
│ 2 │ 이영희 │ 15 │ 2반 │
└────┴─────────┴─────┴────────┘
- 모든 학생이 같은 정보 항목을 가짐

NoSQL = 소셜미디어 프로필
사용자 1: { name: "김철수", age: 15, hobbies: ["독서", "게임"] }
사용자 2: { name: "이영희", city: "서울", job: "학생", pets: 2 }
- 각 사용자가 다른 정보를 가질 수 있음

⚙️ 작동 원리

1. 데이터 구조 비교

-- SQL: 정형화된 테이블
users 테이블
┌────┬─────────┬──────────────────┬─────┐
│ id │ name │ email │ age │
├────┼─────────┼──────────────────┼─────┤
1 │ 김철수 │ chulsoo@mail.com25
2 │ 이영희 │ younghee@mail.com30
└────┴─────────┴──────────────────┴─────┘

orders 테이블
┌────┬─────────┬─────────────┬───────┐
│ id │ user_id │ product │ price │
├────┼─────────┼─────────────┼───────┤
11 │ 노트북 │ 1500
21 │ 마우스 │ 30
└────┴─────────┴─────────────┴───────┘
// NoSQL: 유연한 문서
// MongoDB 예시
{
_id: ObjectId("507f1f77bcf86cd799439011"),
name: "김철수",
email: "chulsoo@mail.com",
age: 25,
orders: [ // 중첩 문서
{
product: "노트북",
price: 1500,
date: "2024-01-15"
},
{
product: "마우스",
price: 30,
date: "2024-01-20"
}
],
preferences: { // 다양한 구조
theme: "dark",
notifications: true
}
}

2. NoSQL 데이터베이스 유형

1. Document DB (문서형)
└─ MongoDB, CouchDB
└─ JSON 형태의 문서 저장

2. Key-Value DB (키-값)
└─ Redis, DynamoDB
└─ 빠른 캐싱, 세션 저장

3. Column-Family DB (컬럼형)
└─ Cassandra, HBase
└─ 대규모 데이터 분석

4. Graph DB (그래프형)
└─ Neo4j, Amazon Neptune
└─ 관계 중심 데이터 (소셜 네트워크)

💡 실제 예시

SQL 예시 (MySQL)

-- 테이블 생성 (엄격한 스키마)
CREATE TABLE users (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(50) NOT NULL,
email VARCHAR(100) UNIQUE NOT NULL,
age INT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

CREATE TABLE orders (
id INT PRIMARY KEY AUTO_INCREMENT,
user_id INT,
product VARCHAR(100),
price DECIMAL(10, 2),
FOREIGN KEY (user_id) REFERENCES users(id)
);

-- 데이터 삽입
INSERT INTO users (name, email, age)
VALUES ('김철수', 'chulsoo@mail.com', 25);

-- JOIN으로 관계 조회
SELECT
users.name,
orders.product,
orders.price
FROM users
INNER JOIN orders ON users.id = orders.user_id
WHERE users.name = '김철수';

-- 트랜잭션 (ACID 보장)
BEGIN TRANSACTION;
UPDATE accounts SET balance = balance - 100 WHERE id = 1;
UPDATE accounts SET balance = balance + 100 WHERE id = 2;
COMMIT;

NoSQL 예시 (MongoDB)

// 스키마 없음 - 자유로운 구조
db.users.insertOne({
name: "김철수",
email: "chulsoo@mail.com",
age: 25,
orders: [
{ product: "노트북", price: 1500 },
{ product: "마우스", price: 30 }
]
});

// 다른 구조도 가능!
db.users.insertOne({
name: "이영희",
email: "younghee@mail.com",
hobbies: ["독서", "여행"], // 다른 필드
address: { // 중첩 객체
city: "서울",
zipcode: "12345"
}
});

// 조회
db.users.find({ name: "김철수" });

// 중첩 문서 조회
db.users.find({
"orders.product": "노트북"
});

// 업데이트
db.users.updateOne(
{ name: "김철수" },
{
$set: { age: 26 },
$push: {
orders: { product: "키보드", price: 80 }
}
}
);

// 집계 (Aggregation)
db.users.aggregate([
{ $unwind: "$orders" },
{ $group: {
_id: "$name",
totalSpent: { $sum: "$orders.price" }
}
}
]);

Node.js에서 SQL vs NoSQL

// ============ SQL (MySQL) ============
const mysql = require('mysql2/promise');

const pool = mysql.createPool({
host: 'localhost',
user: 'root',
password: 'password',
database: 'myapp'
});

// 사용자와 주문 조회 (JOIN 필요)
async function getUserWithOrders(userId) {
const [rows] = await pool.execute(`
SELECT
users.name,
users.email,
orders.product,
orders.price
FROM users
LEFT JOIN orders ON users.id = orders.user_id
WHERE users.id = ?
`, [userId]);

return rows;
}

// ============ NoSQL (MongoDB) ============
const { MongoClient } = require('mongodb');

const client = new MongoClient('mongodb://localhost:27017');
const db = client.db('myapp');
const users = db.collection('users');

// 사용자와 주문 조회 (JOIN 불필요 - 이미 포함됨)
async function getUserWithOrders(userId) {
const user = await users.findOne({ _id: userId });
// user.orders 에 이미 주문 정보 포함!
return user;
}

실전 예시: 블로그 시스템

// ============ SQL 방식 ============
// 정규화된 구조
/*
posts 테이블:
id, title, content, author_id, created_at

comments 테이블:
id, post_id, user_id, content, created_at

tags 테이블:
id, name

post_tags 테이블:
post_id, tag_id
*/

// 게시글 + 댓글 + 태그 조회 → 여러 JOIN 필요
SELECT
posts.*,
comments.content as comment,
tags.name as tag
FROM posts
LEFT JOIN comments ON posts.id = comments.post_id
LEFT JOIN post_tags ON posts.id = post_tags.post_id
LEFT JOIN tags ON post_tags.tag_id = tags.id
WHERE posts.id = 1;

// ============ NoSQL 방식 ============
// 비정규화된 구조
{
_id: ObjectId("..."),
title: "MongoDB 소개",
content: "MongoDB는...",
author: {
id: "user123",
name: "김철수"
},
comments: [
{
user: { id: "user456", name: "이영희" },
content: "좋은 글이네요!",
createdAt: "2024-01-15"
}
],
tags: ["데이터베이스", "NoSQL"],
createdAt: "2024-01-10"
}

// 한 번의 쿼리로 모든 데이터 조회!
db.posts.findOne({ _id: ObjectId("...") });

🤔 자주 묻는 질문

Q1. 어떤 것을 선택해야 하나요?

A: 프로젝트 특성에 따라 선택하세요:

✅ SQL을 선택하는 경우:
├─ 데이터 구조가 명확하고 변하지 않음
├─ 복잡한 관계와 JOIN이 많음
├─ ACID 트랜잭션이 필수 (금융, 전자상거래)
├─ 데이터 무결성이 중요함
└─ 예: 은행 시스템, 회계 프로그램, ERP

✅ NoSQL을 선택하는 경우:
├─ 데이터 구조가 유동적임
├─ 빠른 읽기/쓰기가 중요함
├─ 수평 확장(스케일 아웃)이 필요함
├─ 대용량 데이터 처리
└─ 예: 소셜미디어, IoT, 실시간 분석, 로그

Q2. 주요 차이점은?

A:

특성SQLNoSQL
데이터 구조테이블 (행, 열)문서, 키-값, 그래프 등
스키마고정 (엄격)유연 (동적)
확장수직 확장 (Scale Up)수평 확장 (Scale Out)
관계JOIN으로 연결중첩 또는 참조
트랜잭션ACID 보장최종 일관성 (BASE)
쿼리SQL 언어각 DB마다 다름
예시MySQL, PostgreSQLMongoDB, Redis
// SQL: ACID
Atomicity (원자성): 전부 또는 전무
Consistency (일관성): 규칙 위반 불가
Isolation (독립성): 트랜잭션 간 독립
Durability (영속성): 영구 저장

// NoSQL: BASE
Basically Available (기본적 가용성)
Soft state (유연한 상태)
Eventually consistent (최종 일관성)

Q3. 성능 차이는?

A: 사용 패턴에 따라 다릅니다:

// SQL 장점: 복잡한 쿼리, JOIN
// 여러 테이블에서 데이터 조합
SELECT u.name, p.title, c.content
FROM users u
JOIN posts p ON u.id = p.author_id
JOIN comments c ON p.id = c.post_id
WHERE u.age > 20
ORDER BY p.created_at DESC;
// → 강력하고 정확하지만 느릴 수 있음

// NoSQL 장점: 빠른 읽기/쓰기
// 단일 문서에 모든 정보 포함
db.posts.find({ author_age: { $gt: 20 } })
.sort({ created_at: -1 });
// → 매우 빠르지만 복잡한 JOIN은 어려움

// 벤치마크 예시
SQL: 10,000 reads/sec (복잡한 JOIN)
NoSQL: 100,000 reads/sec (단순 조회)

SQL: 5,000 writes/sec (트랜잭션 보장)
NoSQL: 50,000 writes/sec (빠른 쓰기)

Q4. 함께 사용할 수 있나요?

A: 네! 폴리글랏 퍼시스턴스(Polyglot Persistence)라고 합니다:

// 예: 전자상거래 시스템

// 1. SQL (MySQL) - 주문, 결제
// → ACID 트랜잭션 필수
{
orders: "MySQL",
payments: "PostgreSQL",
inventory: "MySQL"
}

// 2. NoSQL (MongoDB) - 상품 카탈로그
// → 유연한 속성, 빠른 조회
{
products: "MongoDB",
reviews: "MongoDB"
}

// 3. NoSQL (Redis) - 캐싱, 세션
// → 초고속 읽기/쓰기
{
cache: "Redis",
sessions: "Redis",
realtime: "Redis"
}

// 4. Graph DB (Neo4j) - 추천 시스템
// → 관계 기반 쿼리
{
recommendations: "Neo4j",
socialGraph: "Neo4j"
}

Q5. 마이그레이션은 어렵나요?

A: 전략적으로 접근하면 가능합니다:

// SQL → NoSQL 마이그레이션 전략

// 1. 하이브리드 접근
// - 새 기능은 NoSQL
// - 기존 기능은 SQL 유지

// 2. 점진적 마이그레이션
// Step 1: 읽기 전용 데이터부터
// Step 2: 덜 중요한 기능
// Step 3: 핵심 기능

// 3. 데이터 동기화
// - 변경 데이터 캡처 (CDC)
// - 이벤트 스트리밍 (Kafka)

// 예시: 이중 쓰기
async function createUser(userData) {
// SQL에 쓰기
const sqlUser = await mysqlDB.insert(userData);

// NoSQL에도 쓰기 (비동기)
await mongooDB.insertOne({
...userData,
_id: sqlUser.id
}).catch(err => {
// 실패해도 SQL은 유지
console.error('MongoDB sync failed:', err);
});

return sqlUser;
}

🎓 다음 단계

SQL과 NoSQL을 이해했다면, 다음을 학습해보세요:

  1. 데이터베이스란? - 기본 개념
  2. Node.js란? - 백엔드 개발
  3. Docker란? (문서 작성 예정) - 데이터베이스 컨테이너화

실습해보기

# ============ MySQL 실습 ============
# 설치
brew install mysql # macOS

# 실행
mysql -u root -p

# 테이블 생성 및 쿼리
CREATE DATABASE testdb;
USE testdb;
CREATE TABLE users (id INT, name VARCHAR(50));
INSERT INTO users VALUES (1, '김철수');
SELECT * FROM users;

# ============ MongoDB 실습 ============
# 설치
brew tap mongodb/brew
brew install mongodb-community

# 실행
mongod --config /usr/local/etc/mongod.conf

# MongoDB Shell
mongosh

# 데이터 삽입 및 조회
use testdb
db.users.insertOne({ name: "김철수", age: 25 })
db.users.find()

🎬 마무리

SQL과 NoSQL은 각각의 장단점이 있습니다:

  • SQL: 정형화된 데이터, ACID 트랜잭션, 복잡한 관계
  • NoSQL: 유연한 스키마, 빠른 성능, 수평 확장
  • 선택 기준: 데이터 구조, 확장성, 일관성 요구사항
  • 폴리글랏: 필요에 따라 여러 DB 조합 사용

"은탄환은 없다" - 프로젝트에 맞는 데이터베이스를 선택하세요! ⚖️✨