전체 목록
데이터베이스Hard#37

SQL(관계형 DB)과 NoSQL의 차이점과 각각의 적합한 사용 사례를 설명해주세요.

#DB#SQL#NoSQL#아키텍처
힌트

스키마 유연성, 확장 방식, CAP 정리를 생각해보세요.

정답 및 해설

SQL(관계형 DB)과 NoSQL의 차이점과 각각의 적합한 사용 사례를 설명해주세요.

SQL(관계형 데이터베이스)과 NoSQL은 데이터를 저장하고 조회하는 방식에서 근본적으로 다른 철학을 가집니다. 어떤 데이터베이스가 적합한지는 데이터의 구조, 일관성 요구사항, 확장성, 쿼리 패턴에 따라 결정됩니다.

SQL (관계형 데이터베이스)

핵심 특징

**고정 스키마(Fixed Schema)**로 데이터를 저장합니다. 테이블을 생성할 때 컬럼과 데이터 타입을 미리 정의해야 하며, 이 구조에 맞지 않는 데이터는 저장할 수 없습니다.

-- 테이블 생성 시 스키마를 명확히 정의
CREATE TABLE users (
  id        INT PRIMARY KEY AUTO_INCREMENT,
  email     VARCHAR(255) NOT NULL UNIQUE,
  name      VARCHAR(100) NOT NULL,
  age       INT,
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

-- 정규화: 중복을 줄이기 위해 관련 데이터를 별도 테이블로 분리
CREATE TABLE orders (
  id      INT PRIMARY KEY AUTO_INCREMENT,
  user_id INT NOT NULL,
  total   DECIMAL(10, 2),
  status  ENUM('pending', 'completed', 'cancelled'),
  FOREIGN KEY (user_id) REFERENCES users(id)
);

ACID 트랜잭션

SQL 데이터베이스는 ACID 특성을 보장하여 데이터 정합성을 유지합니다.

속성의미예시
Atomicity (원자성)트랜잭션 내 모든 작업이 성공하거나 모두 실패계좌 이체: 출금과 입금이 함께 성공하거나 함께 실패
Consistency (일관성)트랜잭션 전후 데이터가 유효한 상태 유지잔액이 음수가 되지 않도록 제약 조건 유지
Isolation (격리성)동시에 실행되는 트랜잭션이 서로 영향을 주지 않음다른 사용자의 미완성 트랜잭션 결과를 읽지 않음
Durability (지속성)커밋된 트랜잭션은 장애가 발생해도 유지서버가 다운돼도 커밋된 데이터는 보존
-- ACID 트랜잭션 예시: 계좌 이체
BEGIN TRANSACTION;

UPDATE accounts SET balance = balance - 100000 WHERE id = 1;
UPDATE accounts SET balance = balance + 100000 WHERE id = 2;

-- 중간에 오류 발생 시 모두 되돌림
COMMIT;  -- 또는 ROLLBACK;

복잡한 쿼리와 JOIN

여러 테이블에 걸친 복잡한 관계를 SQL로 표현할 수 있습니다.

-- 사용자별 최근 주문과 상품 정보를 함께 조회
SELECT
  u.name,
  o.id AS order_id,
  o.created_at,
  SUM(oi.quantity * oi.price) AS total
FROM users u
JOIN orders o ON u.id = o.user_id
JOIN order_items oi ON o.id = oi.order_id
WHERE o.created_at >= DATE_SUB(NOW(), INTERVAL 30 DAY)
GROUP BY u.id, o.id
ORDER BY o.created_at DESC;

수직 확장 (Scale-Up)

SQL 데이터베이스는 주로 서버 자체의 하드웨어 성능을 높이는 방식으로 확장합니다. 수평 확장(샤딩)도 가능하지만 복잡도가 높습니다.

NoSQL

핵심 특징

유연한 스키마(Flexible Schema) 를 가집니다. 컬럼을 미리 정의하지 않아도 되며, 문서마다 다른 구조를 가질 수 있습니다.

NoSQL의 4가지 데이터 모델

1. 문서 기반 (Document) — MongoDB, CouchDB

JSON 유사 형태의 문서로 데이터를 저장합니다. 중첩된 구조를 그대로 저장할 수 있어 계층적 데이터에 자연스럽습니다.

// MongoDB 문서 예시 — 중첩 구조를 그대로 저장
{
  "_id": "user_123",
  "email": "user@example.com",
  "name": "홍길동",
  "address": {
    "city": "서울",
    "district": "강남구",
    "zip": "06100"
  },
  "tags": ["premium", "vip"],
  "orders": [
    { "id": "ord_001", "total": 50000, "status": "completed" },
    { "id": "ord_002", "total": 30000, "status": "pending" }
  ]
}

// 조회
db.users.find({ "address.city": "서울", "tags": "premium" });

2. 키-값 기반 (Key-Value) — Redis, DynamoDB

가장 단순한 구조로, 키로 값을 저장하고 조회합니다. 매우 빠른 속도가 장점입니다.

SET user:session:abc123 '{"userId": 42, "role": "admin"}' EX 3600
GET user:session:abc123

3. 컬럼 기반 (Wide-Column) — Apache Cassandra, HBase

행 단위가 아닌 컬럼 패밀리 단위로 데이터를 저장합니다. 대용량 쓰기와 분산 처리에 강점이 있습니다.

4. 그래프 기반 (Graph) — Neo4j

노드(데이터)와 엣지(관계)로 데이터를 표현합니다. 소셜 네트워크, 추천 시스템처럼 관계 탐색이 핵심인 경우에 적합합니다.

// Neo4j Cypher 쿼리 — "홍길동의 친구의 친구" 찾기
MATCH (user:Person {name: "홍길동"})-[:FRIENDS_WITH*2]-(fof)
WHERE NOT (user)-[:FRIENDS_WITH]-(fof)
RETURN fof.name

수평 확장 (Scale-Out)

NoSQL은 샤딩(Sharding) 을 통한 수평 확장을 기본적으로 지원합니다. 데이터를 여러 서버에 분산 저장하여 트래픽과 데이터양이 늘어나도 서버를 추가하는 방식으로 대응할 수 있습니다.

CAP 정리

분산 시스템에서는 Consistency(일관성), Availability(가용성), Partition Tolerance(분단 내성) 를 동시에 모두 만족할 수 없습니다. NoSQL은 대개 일관성을 약간 희생하고 가용성과 분단 내성을 선택합니다(최종 일관성, Eventual Consistency).

SQL vs NoSQL 비교

항목SQL (RDBMS)NoSQL
스키마고정 (변경 시 마이그레이션 필요)유연 (동적으로 변경 가능)
데이터 모델테이블 (행/열)문서, 키-값, 컬럼, 그래프
트랜잭션ACID 완전 지원제한적 (일부 지원, Eventual Consistency)
확장 방식수직 확장 (주로)수평 확장 (기본 지원)
JOIN복잡한 JOIN 지원대부분 JOIN 미지원
쿼리 언어SQL (표준화)DB마다 다름
대표 제품MySQL, PostgreSQL, OracleMongoDB, Redis, Cassandra, DynamoDB

적합한 사용 사례

SQL을 선택해야 할 때

데이터 간 관계가 복잡하고, 정합성이 중요할 때 SQL이 적합합니다.

  • 금융 시스템: 계좌 이체, 결제 처리 — ACID 트랜잭션 필수
  • 전자상거래: 주문, 결제, 재고 관리 — 복잡한 관계와 정합성 필요
  • ERP/CRM: 고객, 계약, 청구서 관리 — 정규화된 데이터 구조
  • 인사관리 시스템: 직원, 부서, 급여 — 관계형 데이터
-- 전자상거래: 재고 차감과 주문 생성을 원자적으로 처리
BEGIN;
  INSERT INTO orders (user_id, product_id, quantity) VALUES (1, 42, 2);
  UPDATE products SET stock = stock - 2 WHERE id = 42 AND stock >= 2;
  -- 재고가 부족하면 ROLLBACK
COMMIT;

NoSQL을 선택해야 할 때

대용량, 비정형 데이터, 빠른 읽기/쓰기, 유연한 구조가 필요할 때 NoSQL이 적합합니다.

  • 세션/캐시 저장: Redis — 빠른 키-값 접근, 만료 시간 설정
  • 콘텐츠 관리 시스템: MongoDB — 구조가 다양한 게시글, 설정 데이터
  • 실시간 분석 / 이벤트 로그: Cassandra — 대용량 쓰기, 시계열 데이터
  • 소셜 네트워크: Neo4j — 팔로우/팔로워, 추천 알고리즘
  • IoT 데이터: 빠른 속도로 쌓이는 센서 데이터
// MongoDB: 상품마다 다른 속성을 유연하게 저장
db.products.insertMany([
  { name: "맥북 프로", category: "노트북", specs: { ram: "16GB", cpu: "M3 Pro" } },
  { name: "청바지", category: "의류", specs: { size: "32", color: "blue" } },
  // 카테고리마다 완전히 다른 속성 — SQL에서는 비효율적
]);

선택 기준 정리

데이터 구조가 명확하고 관계가 복잡한가?   → SQL
데이터 정합성(ACID)이 최우선인가?         → SQL
데이터 구조가 자주 바뀌거나 비정형인가?   → NoSQL
초당 수만 건의 쓰기가 필요한가?           → NoSQL (Cassandra 등)
단순 캐싱/세션 저장이 목적인가?           → NoSQL (Redis)
관계 탐색이 핵심 기능인가?               → NoSQL (Graph DB)

실제로 대규모 시스템에서는 SQL과 NoSQL을 함께 사용하는 경우가 많습니다. 예를 들어 핵심 비즈니스 데이터는 PostgreSQL에, 세션과 캐시는 Redis에, 로그와 분석 데이터는 Cassandra에 저장하는 방식으로 각 DB의 장점을 활용합니다.