01 — SQL & JOIN

SQL & JOIN 연산

관계형 데이터베이스의 핵심인 SQL과 JOIN 연산을 직접 실행하며 결과를 확인해 보세요. INNER, LEFT, RIGHT JOIN의 차이를 시각적으로 학습합니다.

TABLE: users
idnameage
1Alice28
2Bob34
3Carol22
4Dave41
TABLE: orders
iduser_idproductamount
1011Laptop1200
1022Mouse35
1031Monitor450
1045Keyboard85
JOIN 유형:
WHERE:
QUERY RESULT
02 — NORMALIZATION

정규화 (Normalization)

중복 데이터와 이상 현상을 없애기 위해 테이블을 단계적으로 분해합니다. 비정규화 → 1NF → 2NF → 3NF로 변환하는 과정을 직접 확인해 보세요.

비정규화
UNF
1차 정규형
1NF
2차 정규형
2NF
3차 정규형
3NF
주문 테이블 (비정규화 — UNF)
주문ID고객명도시우편번호상품목록총액
1001Alice서울04524Laptop, Mouse1235
1002Bob부산48058Monitor450
1003Alice서울04524Keyboard85
문제점:
· 상품목록이 다중값 (Laptop, Mouse → 원자값이 아님) — 1NF 위반
· Alice 정보(도시, 우편번호)가 여러 행에 중복 — 갱신 이상
· 주문이 삭제되면 고객 정보도 사라짐 — 삭제 이상
주문 테이블 (1NF — 원자값 보장)
주문ID고객명도시우편번호상품금액
1001Alice서울04524Laptop1200
1001Alice서울04524Mouse35
1002Bob부산48058Monitor450
1003Alice서울04524Keyboard85
1NF 적용: 다중값 속성 분리 → 각 셀이 원자값(단일값)을 가짐
남은 문제: 복합 기본키 (주문ID, 상품) 중 고객 정보는 주문ID에만 의존 — 부분 종속 (2NF 위반)
고객 테이블 (Customers)
고객명 (PK)도시우편번호
Alice서울04524
Bob부산48058
주문상품 테이블 (OrderItems)
주문ID고객명 (FK)상품금액
1001AliceLaptop1200
1001AliceMouse35
1002BobMonitor450
1003AliceKeyboard85
2NF 적용: 부분 종속 제거 → 고객 정보를 별도 테이블로 분리
남은 문제: 우편번호(04524)가 도시(서울)를 결정 — 이행적 종속 (3NF 위반)
지역 테이블 (Locations)
우편번호 (PK)도시
04524서울
48058부산
고객 테이블 (Customers)
고객명 (PK)우편번호 (FK)
Alice04524
Bob48058
주문상품 테이블 (OrderItems)
주문ID고객명 (FK)상품금액
1001AliceLaptop1200
1001AliceMouse35
1002BobMonitor450
1003AliceKeyboard85
3NF 적용 완료! 이행적 종속 제거 → 우편번호↔도시 관계를 별도 테이블로 분리
· 모든 비키 속성이 기본키에만 직접 종속 · 중복 없음 · 이상 현상 해소
03 — TRANSACTION & ACID

트랜잭션 & ACID

트랜잭션은 데이터베이스의 상태를 변환하는 하나의 논리적 작업 단위입니다. ACID 속성이 데이터 무결성을 어떻게 보장하는지 시뮬레이션으로 확인하세요.

A
ATOMICITY
트랜잭션 내 모든 연산은
전부 성공하거나
전부 실패합니다
C
CONSISTENCY
트랜잭션 전후로
데이터베이스가 항상
일관된 상태를 유지합니다
I
ISOLATION
동시 실행 중인 트랜잭션은
서로 간섭하지 않습니다
(격리 수준으로 제어)
D
DURABILITY
커밋된 트랜잭션의 결과는
장애 발생 시에도
영구적으로 보존됩니다
트랜잭션 시뮬레이션
현재 DB 상태 (accounts 테이블)
Alice 잔액: ₩1,000
Bob 잔액: ₩500
총합: ₩1,500
상태:
IDLE
ACTIVE
COMMITTED
ROLLED BACK
-- 트랜잭션을 시작하려면 BEGIN 버튼을 클릭하세요
격리 수준 (Isolation Levels)
격리 수준 Dirty Read Non-Repeatable Read Phantom Read 설명
READ UNCOMMITTED 발생 발생 발생 커밋 안 된 데이터 읽기 가능
READ COMMITTED 없음 발생 발생 커밋된 데이터만 읽음 (기본값)
REPEATABLE READ 없음 없음 발생 같은 쿼리는 같은 결과 보장
SERIALIZABLE 없음 없음 없음 완전 격리, 성능 비용 높음
Dirty Read: 아직 커밋되지 않은 데이터를 다른 트랜잭션이 읽는 현상
Non-Repeatable Read: 같은 트랜잭션에서 같은 row를 두 번 읽었을 때 값이 달라지는 현상
Phantom Read: 같은 트랜잭션에서 같은 쿼리를 두 번 실행했을 때 없던 행이 생기는 현상
04 — INDEX

인덱스 (Index)

인덱스는 데이터 검색 속도를 높이는 자료구조입니다. B+ Tree 구조와 Full Table Scan vs Index Scan의 성능 차이를 직접 비교해 보세요.

B+ Tree 인덱스 구조 (age 컬럼)
25 40
20
30
50
18 20
22 25
28 30
34 40
41 50
리프 노드는 실제 데이터 포인터를 가지며 연결 리스트로 이어져 범위 검색에 유리합니다
Full Table Scan vs Index Scan
검색 조건: WHERE age = 34
Full Table Scan
모든 행 순차 검사
Index Scan
B+ Tree 경로 탐색
복합 인덱스 (Composite Index)
INDEX(city, age) — 왼쪽 접두사 규칙: 가장 왼쪽 컬럼부터 순서대로 사용해야 인덱스가 적용됩니다
city = '서울' 인덱스 사용 O (city는 첫 번째 컬럼)
city = '서울' AND age = 28 인덱스 사용 O (두 컬럼 모두 활용)
age = 28 인덱스 사용 X (city 없이 age만 조회)
city LIKE '%서울%' 인덱스 사용 X (앞에 % 와일드카드)
05 — NoSQL vs SQL

NoSQL vs SQL

관계형 DB와 NoSQL DB의 차이를 비교하고, Redis의 다양한 데이터 구조와 분산 시스템의 CAP 정리를 시각적으로 이해합니다.

SQL vs NoSQL 비교
항목 SQL (관계형 DB) NoSQL
스키마 고정 스키마 (ALTER TABLE 필요) 유연한 스키마 (필드 자유롭게 추가)
데이터 모델 테이블 (행 & 열) Document, Key-Value, Graph, Column
확장 방식 수직 확장 (Scale-Up) 주로 사용 수평 확장 (Scale-Out) 용이
ACID 완전 지원 부분 지원 (BASE 모델)
JOIN 자유로운 JOIN 연산 JOIN 미지원 (비정규화로 해결)
쿼리 언어 SQL 표준 DB마다 고유 API (통일 없음)
주요 사용처 금융, ERP, 전자상거래 (강한 일관성) SNS, 실시간 채팅, 빅데이터, 캐시
대표 제품 MySQL, PostgreSQL, Oracle MongoDB, Redis, Cassandra, DynamoDB
Redis 데이터 구조
String
List
Set
Hash
Sorted Set
가장 기본적인 자료형. 문자열, 숫자, 직렬화된 JSON 등 저장
user:1:name = "Alice" SET user:1:name "Alice"
user:1:age = 28 INCR user:1:age → 29
session:abc123 = "token_xyz" TTL:3600s SETEX (만료 시간 포함)
사용: 세션 토큰, 카운터, 캐시, 분산 락
양방향 연결 리스트. LPUSH/RPUSH로 삽입, LPOP/RPOP으로 제거
feed:timeline → [0] → [1] → [2] → [3] → [4]
[0] "뉴스C (최신)"
[1] "뉴스B"
[2] "뉴스A"
[3] "뉴스Z"
[4] "뉴스Y (오래됨)"
LPUSH feed:timeline "뉴스C"  |  LRANGE feed:timeline 0 9  |  LTRIM feed:timeline 0 99
사용: 뉴스피드, 메시지 큐, 최근 방문 기록
중복 없는 집합. 교집합/합집합/차집합 연산 지원
tags:post:1 (순서 없음, 중복 불가)
javascript
database
redis
nosql
backend
SADD tags:post:1 "redis"  |  SISMEMBER → 존재 여부
SINTER tags:post:1 tags:post:2 → 공통 태그 (교집합)
사용: 태그 시스템, 팔로워/팔로잉, 좋아요 목록, 방문자 집합
필드-값 쌍의 맵. 객체를 효율적으로 저장 (각 필드 개별 접근 가능)
user:1001
name"Alice"
age28
city"서울"
score9850
HSET user:1001 name "Alice" age 28
HGET user:1001 name → "Alice"
HINCRBY user:1001 score 150 → 10000
사용: 사용자 프로필, 상품 정보, 설정값 저장
각 멤버에 점수(score)를 부여해 정렬된 집합. 범위 조회 O(log N)
leaderboard:game (score 기준 정렬)
#1Alice9850
#2Carol7200
#3Bob5500
#4Dave3100
ZADD leaderboard 9850 "Alice"
ZREVRANK leaderboard "Bob" → 2 (0-indexed)
ZREVRANGE leaderboard 0 9 WITHSCORES → Top 10
사용: 실시간 리더보드, 우선순위 큐, 시간순 피드
CAP 정리 (CAP Theorem)
C Consistency A Availability P Partition Tolerance CP HBase MongoDB Redis AP Cassandra DynamoDB CouchDB CA MySQL · PostgreSQL 분산 환경에서 P(Partition Tolerance)는 필수 — CA 선택 불가
C
Consistency
모든 노드가 동시에 같은 데이터를 볼 수 있음. 읽기 요청은 항상 최신 쓰기 결과를 반환
A
Availability
모든 요청에 항상 응답. 일부 노드가 장애여도 시스템이 응답을 반환 (오래된 데이터일 수 있음)
P
Partition Tolerance
네트워크 분단(파티션) 발생 시에도 시스템이 동작 지속. 분산 시스템에서 사실상 필수
CAP 정리: 분산 시스템은 Consistency, Availability, Partition Tolerance 중 동시에 2가지만 보장할 수 있습니다. 실제 분산 환경에서 P는 피할 수 없으므로, C와 A 중 어느 쪽을 우선할지 선택해야 합니다.