🎯 F-lab Java 13주차 학습 커리큘럼

13주차 자료의 모든 토픽을 "DB 이론 → SQL 성능"의 두 축으로 재배열한 학습 경로.
12주차까지 Java/Spring/JPA를 다뤘다면, 13주차는 데이터베이스의 펀더멘털로 방향 전환.

1) Part A — DB 이론과 관리 (모델링, 정규화, NoSQL, 분산 시스템 이론, 락)
2) Part B — SQL 성능 최적화 (옵티마이저, 인덱스, B-tree, EXPLAIN)

JPA가 추상화해서 가려놓았던 DB 본연의 영역을 정면으로 보는 주차다.


📊 학습 경로 한눈에 보기

[Part A — DB 이론과 관리]
  [Phase 1] DB 핵심 용어와 모델링 (엔티티/릴레이션/스키마)
     ↓
  [Phase 2] 정규화 (1NF → 2NF → 3NF → BCNF)
     ↓
  [Phase 3] 이상 현상과 정규화 평가
     ↓
  [Phase 4] SQL Injection 보안
     ↓
  [Phase 5] RDBMS와 NoSQL (Scale-Up vs Scale-Out)
     ↓
  [Phase 6] 분산 시스템 이론 + 락 (BASE/CAP/PACELC + S/X Lock)

[Part B — SQL 성능 최적화]
  [Phase 7] 옵티마이저 (RBO/CBO + 동작 6단계)
     ↓
  [Phase 8] 인덱스 기초 (빅오, B-tree) ◄ 정점 1
     ↓
  [Phase 9] 멀티컬럼 인덱스와 EXPLAIN
     ↓
  [Phase 10] 인덱스 최적화 전략 (Covering Index, Full Scan 선택)

총 10 Phase × 31 Unit — 단일 주차로는 큰 분량 (Part A/B 구조).

🔗 1~13주차 흐름 정리

주차주제핵심 변화
1주차OOP·JVM·GC·컬렉션·I/O 개론자바 큰 그림
2주차JVM 내부·바이트코드·G1 GC"어떻게 돌아가나"
3주차컬렉션·제네릭·함수형자바 표현력
4주차멀티스레딩·동시성·Executor동시성 정복
5주차Atomic + Spring IoC/DI 입문자바 → Spring 다리
6주차테스트 + 웹 인프라 + DB 접근 진화Spring 실전 환경
7주차JPA/ORM 입문 + 트랜잭션 추상화DB 추상화 입문
8주차프록시의 진화AOP 메커니즘
9주차Spring AOP 실전 + 트랜잭션 전파AOP 실전 활용
10주차트랜잭션 정리 + 빈 라이프사이클 함정 + 격리 수준트랜잭션 마무리
11주차JPA의 정체와 영속성 컨텍스트JPA 메커니즘 완전 이해
12주차연관관계 + N+1 등 성능 최적화JPA 실전 활용
13주차 (지금)DB 펀더멘털 - 모델링부터 인덱스까지DB 본연의 영역으로

🗓️ 권장 학습 일정 (압축 7일)

DayPhase학습 목표
Part A
1일차Phase 1 + 2DB 용어 + 정규화 (1NF~BCNF)
2일차Phase 3 + 4이상 현상 + SQL Injection
3일차Phase 5RDBMS와 NoSQL (Scale, Redis)
4일차Phase 6BASE/CAP/PACELC + 공유락/베타락
Part B
5일차Phase 7 + 8옵티마이저 + 인덱스 기초 (B-tree) ★
6일차Phase 9멀티컬럼 인덱스 + EXPLAIN
7일차Phase 10 + 종합Covering Index + 인덱스 최적화 + 자기 점검

여유 일정 (10일): Phase 8과 Phase 9에 각 +1일. 인덱스는 직접 SQL을 돌리며 EXPLAIN으로 확인해야 체화됨.


🌱 Part A — DB 이론과 관리

📚 Phase 1 — DB 핵심 용어와 모델링

목표: JPA가 가려놓았던 DB의 기본 어휘를 정확히 잡는다.

Unit 1.1 — 엔티티 vs 릴레이션

선수 지식: 6주차 Phase 6 (DB 기초), 11주차 Phase 3

핵심 개념

엔티티(Entity):

  • 개념적 표현
  • 속성들의 집합 — 설계 단계의 추상
  • 예: 학생 = (학번, 이름, 학년, 전공) 의 집합

릴레이션(Relation):

  • 물리적 표현
  • 실제 데이터가 들어가는 테이블
  • 예: students 테이블의 행과 열

비유:

"엔티티는 클래스, 릴레이션은 인스턴스의 모임(테이블)"

ILIC 사례:

  • 엔티티: Booking 객체 (개념)
  • 릴레이션: bookings 테이블 (물리)
  • → 11주차 Phase 3에서 @Entity 가 이 두 개념을 잇는 다리

자기 점검

  • 7주차의 @Entity 어노테이션이 매핑하는 두 세계는?
  • 엔티티와 릴레이션이 1:1 매핑이 안 되는 경우는? (힌트: 슈퍼타입/서브타입)

Unit 1.2 — 어트리뷰트·차수·튜플·카디널리티·도메인

선수 지식: Unit 1.1

핵심 5가지 용어 ⭐ :

용어의미예시 (고객 테이블)
어트리뷰트(Attribute)속성 = 열(Column)이름, 전화번호, 주소
차수(Degree)어트리뷰트의 개수4
튜플(Tuple) = 레코드행(Row) 하나김철수, 010-..., 서울
카디널리티(Cardinality)튜플의 개수1000
도메인(Domain)어트리뷰트가 가질 수 있는 값의 집합안경 착용 = {유, 무}

핵심 차이:

  • 차수 vs 카디널리티:
    • 차수 = 열 수 (변하지 않음)
    • 카디널리티 = 행 수 (변함, 빈 테이블도 가능)

도메인 예시:

CREATE TABLE customer (
    glasses VARCHAR(2) CHECK (glasses IN ('유', '무'))  -- 도메인 = {유, 무}
);

→ JPA로 표현하면 enum 또는 @Check 어노테이션

자기 점검

  • 차수의 최소값은? (힌트: 1)
  • 카디널리티의 최소값은? (힌트: 0)
  • ILIC의 bookings 테이블의 차수와 카디널리티는?

Unit 1.3 — 스키마 3계층 (개념적/논리적/물리적)

선수 지식: Unit 1.2

핵심 개념

스키마:

"데이터베이스의 데이터 구조 정의"

3계층 구조 ⭐ :

계층정의표현 방식
개념적 스키마모든 사용자 공유 구조ERD (Entity-Relationship Diagram)
논리적 스키마특정 DB 모델로 변환SQL DDL 구문
물리적 스키마디스크 저장 방식인덱스, 파티션, 클러스터링

예시 흐름:

[설계] 고객 ↔ 주문 (1:N) — ERD
     ↓
[변환] CREATE TABLE customer (...);  -- DDL
       CREATE TABLE order (...);
     ↓
[저장] B-tree 인덱스, 페이지 크기 16KB, ...

스키마 vs 데이터베이스의 관계:

  • MySQL: 데이터베이스 = 스키마 (1:1)
  • PostgreSQL/Oracle: 1 데이터베이스 → N 스키마

자기 점검

  • ILIC의 ERD는 어느 계층인가?
  • "물리적 스키마가 성능에 영향을 준다"의 의미는? (힌트: 인덱스, 파티셔닝)

📚 Phase 2 — 정규화 (1NF → BCNF)

목표: 데이터 중복을 줄이고 이상 현상을 제거하는 단계적 분해 기법을 마스터한다. 면접 단골.

Unit 2.1 — 정규화의 정의와 목적

선수 지식: Phase 1

핵심 개념

정규화(Normalization):

"속성 간 종속 관계를 분석하여 여러 릴레이션으로 분해 하는 과정"

목적:

  • 중복 제거
  • 이상 현상(Anomaly) 방지 (Phase 3에서)
  • 데이터 무결성

단계적 분해 ⭐ :

원본 → 1NF → 2NF → 3NF → BCNF → ... (4NF, 5NF는 거의 안 씀)

실무 권장:

  • 3NF 또는 BCNF 까지 가 일반적
  • 너무 엄격하면 JOIN 폭증 → 반정규화 검토

자기 점검

  • "정규화는 좋다, 그런데 항상 좋은가?"의 답은? (힌트: 트레이드오프)
  • 11주차 임베디드 타입과 정규화의 관계는? (힌트: 임베디드는 비정규화 형태)

Unit 2.2 — 제1정규형 (1NF) — 원자값

선수 지식: Unit 2.1

핵심 규칙:

"테이블의 모든 컬럼이 원자값(Atomic Value) 을 가져야 한다"

위반 사례:

이름취미
김연아인터넷
추신수영화, 음악 ← 원자값 X!
박세리음악, 쇼핑

1NF 적용 후:

이름취미
김연아인터넷
추신수영화
추신수음악
박세리음악
박세리쇼핑

모범 사례:

  • 한 컬럼에 여러 값을 콤마로 저장 X
  • 배열/리스트는 별도 테이블로

현대 DB의 예외 (참고):

  • PostgreSQL ARRAY 타입
  • MySQL JSON 컬럼
  • → 1NF의 엄격한 정의는 흐려지는 추세, 그러나 정규화 정신은 유효

자기 점검

  • ILIC에서 1NF를 위반할 만한 사례는? (힌트: 콤마로 구분된 코드 목록)
  • JSON 컬럼은 1NF 위반인가?

Unit 2.3 — 제2정규형 (2NF) — 부분 함수 종속 제거

선수 지식: Unit 2.2

핵심 규칙:

"1NF + 기본 키의 일부에만 종속된 속성을 다른 테이블로 분리"

전제: 기본 키가 복합 키(composite key)일 때 의미가 있음

위반 사례:

기본 키 = (학생ID, 강의명)

학생ID강의명학생명교수명
101데이터베이스Alice김교수
101운영체제Alice박교수

종속 분석:

  • 학생명학생ID 만으로 결정 ← 부분 함수 종속
  • 교수명강의명 만으로 결정 ← 부분 함수 종속

2NF 적용 — 3개 테이블로 분리:

[학생 테이블] (학생ID 기본 키)
| 학생ID | 학생명 |
|---|---|
| 101 | Alice |

[강의 테이블] (강의명 기본 키)
| 강의명 | 교수명 |
|---|---|
| 데이터베이스 | 김교수 |

[수강 테이블] (학생ID, 강의명 복합 키)
| 학생ID | 강의명 |
|---|---|
| 101 | 데이터베이스 |
| 101 | 운영체제 |

핵심 통찰:

"부분 함수 종속 = 복합 키의 일부분에만 의존하는 속성"

자기 점검

  • 단일 키 테이블은 자동으로 2NF인가? (힌트: YES, 부분 종속 정의 자체가 안 됨)
  • ILIC의 운임 항목 테이블 (운임ID + 항목코드 복합 키) 에서 부분 종속이 있는지 검토

Unit 2.4 — 제3정규형 (3NF) + BCNF

선수 지식: Unit 2.3

핵심 규칙 (3NF):

"2NF + 기본 키가 아닌 속성이 이행 함수 종속(Transitive Dependency) 되지 않음"

이행 함수 종속:

"A → B 이고 B → C 일 때 A → C 인 관계"

위반 사례 (기본 키 = 이름):

이름학과등록금
철수기계공학350
영희수학250
민수화학공학300

종속 분석:

  • 이름 → 학과
  • 학과 → 등록금
  • → 이름 → 등록금 (이행적!)

문제:

  • 철수가 기계공학 → 수학 으로 변경 시 → 등록금도 함께 변경 필요
  • 데이터 갱신 일관성 깨짐

3NF 적용:

[학생 테이블]
| 이름 | 학과 |
|---|---|
| 철수 | 기계공학 |

[학과 테이블]
| 학과 | 등록금 |
|---|---|
| 기계공학 | 350 |


BCNF (Boyce-Codd Normal Form):

"3NF + 모든 결정자가 후보 키여야 함"

용어:

  • 결정자(Determinant): 다른 속성을 유일하게 결정할 수 있는 속성
  • 후보 키(Candidate Key): 각 행을 유일하게 식별 가능한 속성(조합)

위반 사례:

학생번호과목지도교수

후보 키: (학생번호, 과목) → 지도교수 결정 가능
하지만: 지도교수 → 과목 도 결정 가능

  • 그런데 지도교수는 후보 키가 아님!

→ BCNF 위반

BCNF 적용:

  • 지도교수 ↔ 과목 별도 테이블
  • 학생-지도교수 별도 테이블

실무 결론:

"보통 3NF까지 정규화. BCNF는 특수 상황"

자기 점검

  • 1NF/2NF/3NF/BCNF의 차이를 한 줄씩으로 요약하라
  • 3NF와 BCNF가 다른 결과를 내는 사례가 흔한가? (힌트: 드물지만 존재)

📚 Phase 3 — 이상 현상과 정규화 평가

목표: 정규화의 동기(왜 필요한가)와 한계(언제 안 좋은가)를 모두 본다.

Unit 3.1 — 3가지 이상 현상 (삽입/갱신/삭제)

선수 지식: Phase 2

핵심 3가지 ⭐ :

삽입 이상(Insertion Anomaly):

"특정 데이터 삽입 시 불필요한 데이터 까지 함께 입력해야 함"

예: "알고리즘" 신규 과목을 추가하려는데 학생이 없으면 NULL을 넣거나 더미 학생 정보 필요

갱신 이상(Update Anomaly):

"데이터 수정 시 여러 레코드를 모두 수정해야 함 — 일부만 수정 시 불일치"

예: 김교수의 연락처 변경 시 김교수가 가르치는 모든 강의 레코드 갱신 필요

UPDATE 강의정보 SET 교수연락처 = '...' WHERE 교수ID = 1;
-- 5개 레코드 모두 갱신 — 일부 누락 시 불일치

삭제 이상(Deletion Anomaly):

"특정 데이터 삭제 시 의도하지 않은 데이터 까지 함께 삭제됨"

예: 학생이 수강 취소 → 그 학생이 마지막 수강자였다면 → 과목 정보까지 사라짐

3가지가 발생하는 근본 원인:

"서로 다른 의미의 정보가 한 테이블에 묶여 있음"

정규화 가 해결 ⭐

ILIC 관점 점검:

  • 운임 + 운임 항목이 한 테이블에 있다면? → 삽입/갱신/삭제 이상 가능
  • 11주차에서 이미 분리되어 있을 가능성 높음 (정규화된 설계)

자기 점검

  • 3가지 이상 현상이 모두 같은 원인에서 비롯되는 이유는?
  • 이상 현상이 발생해도 좋은 케이스가 있을까? (힌트: 분석용 마트, 비정규화 의도적)

Unit 3.2 — 정규화 장단점 + 반정규화

선수 지식: Unit 3.1

핵심 평가

장점:

  • 이상 현상 제거
  • 데이터 일관성
  • 확장 시 구조 변경 최소화
  • 한 테이블의 용량 최소화 → 캐시 효율

단점:

  • JOIN 증가 → 응답 시간 ↑
  • 복잡한 통계 쿼리 어려움
  • 그러나 데이터 압축 효과로 응답 빨라질 수도 (양면)

반정규화(Denormalization):

"성능을 위해 의도적으로 일부 데이터 중복 허용"

언제 반정규화?:
1. 자주 함께 조회되는 데이터 → JOIN 비용 절감
2. 통계 마트, 보고서용 테이블
3. 읽기 비율이 압도적으로 높은 테이블

ILIC 사례:

  • 운임 + 운임 통화/금액 → 운임 테이블에 직접 저장 (임베디드 타입)
  • 검색용 마트 테이블 별도 생성 가능

원칙:

"정규화 후 반정규화 — 절대 처음부터 비정규화로 시작하지 말 것"

자기 점검

  • 11주차 임베디드 타입 (@Embeddable)이 반정규화 사례인가? (힌트: 일종의 그렇다)
  • 반정규화의 가장 큰 위험은? (힌트: 갱신 이상)

📚 Phase 4 — SQL Injection 보안

목표: 가장 흔한 웹 보안 취약점을 이해하고 표준 방어법을 익힌다.

Unit 4.1 — SQL Injection 공격 메커니즘

선수 지식: 6주차 Phase 7 (JdbcTemplate)

핵심 개념

SQL Injection:

"사용자 입력에 악의적인 SQL 코드를 주입 하여 쿼리를 조작하는 공격"

취약 코드:

String username = request.getParameter("username");
String query = "SELECT * FROM users WHERE username = '" + username + "'";
//                                                    ↑ 직접 문자열 결합 (위험!)

Statement stmt = connection.createStatement();
ResultSet rs = stmt.executeQuery(query);

공격 시나리오:

  • 공격자가 username 필드에 ' OR '1'='1 입력
  • 쿼리가 다음과 같이 변환:
SELECT * FROM users WHERE username = '' OR '1'='1'
--                              ↑ 항상 참 → 모든 사용자 조회!

다른 공격 패턴:

  • '; DROP TABLE users; -- → 테이블 삭제
  • ' UNION SELECT password FROM admins -- → 권한 우회

피해:

  • 데이터 탈취 (비밀번호, 개인정보)
  • 데이터 변조/삭제
  • 시스템 권한 탈취

자기 점검

  • 왜 문자열 결합이 SQL Injection을 일으키는가?
  • ILIC의 어떤 입력 필드가 잠재적 공격 지점인가? (힌트: 검색 조건)

Unit 4.2 — Prepared Statement + 다층 방어

선수 지식: Unit 4.1

핵심 방어 — Prepared Statement ⭐ :

String sql = "SELECT * FROM users WHERE username = ? AND password = ?";
PreparedStatement pstmt = connection.prepareStatement(sql);
pstmt.setString(1, username);  // 입력값이 SQL이 아닌 데이터로 인식
pstmt.setString(2, password);
ResultSet rs = pstmt.executeQuery();

왜 안전한가:

  • SQL 쿼리가 미리 컴파일
  • 이후 입력값은 데이터로만 처리 (SQL 키워드 X)
  • ', ;, -- 등이 자동 이스케이프

JPA의 자동 적용:

  • JPQL의 파라미터 바인딩 (:userName)
  • → JPA를 쓰면 자동으로 Prepared Statement 사용
  • → JPA가 SQL Injection 위험을 줄여주는 부수 효과

다층 방어 (Defense in Depth):

  1. Prepared Statement (가장 중요) ⭐
  2. 입력값 검증/필터링:
public static String sanitizeInput(String input) {
    return input.replaceAll("[^a-zA-Z0-9]", "");  // 영숫자만
}
  1. 에러 메시지 숨기기: 운영 환경에서 SQL 에러 노출 X
  2. 최소 권한 원칙: DB 계정에 필요한 권한만
  3. WAF (Web Application Firewall)

Spring Security의 도움:

  • 입력 검증 어노테이션 (@Valid, @Pattern)
  • CSRF/XSS 같이 다른 보안 위협도 함께 방어

자기 점검

  • PreparedStatement를 쓰면 정말 100% 안전한가? (힌트: 동적 테이블명/컬럼명은 여전히 위험)
  • ILIC에서 모든 SQL은 Prepared Statement를 쓰고 있는가? (JPA 사용 시 YES)

📚 Phase 5 — RDBMS와 NoSQL

목표: 데이터 저장의 두 패러다임을 비교하고, ILIC가 왜 RDBMS인지 이해한다.

Unit 5.1 — RDBMS 특징과 4가지 제약조건

선수 지식: 6주차 Phase 6, 10주차 Phase 5

핵심 정의

RDBMS (Relational Database Management System):

"데이터를 테이블 형태로 저장하고 관계를 정의하여 관리"

4가지 핵심 특징:

  1. 테이블 구조: 행(Row) + 열(Column)
  2. 데이터 무결성 — 5가지 제약조건:
제약의미
PRIMARY KEY행 식별, 중복/NULL 불가
FOREIGN KEY다른 테이블 참조
UNIQUE중복 방지
NOT NULL필수 입력
CHECK값 범위/조건 검증
  1. SQL 지원: 표준 쿼리 언어
  2. ACID 트랜잭션 (6주차 + 10주차 격리 수준):
    • Atomicity (원자성)
    • Consistency (일관성)
    • Isolation (격리성)
    • Durability (지속성)

대표 RDBMS:

  • MySQL ⭐ (ILIC 사용 추정)
  • PostgreSQL
  • Oracle
  • SQL Server
  • MariaDB

자기 점검

  • ACID의 'C'와 정규화의 무결성 보장은 어떤 관계인가?
  • 외래 키 제약조건을 끄면 어떤 사고가? (힌트: 고아 행)

Unit 5.2 — Scale-Up vs Scale-Out ⭐

선수 지식: Unit 5.1

핵심 비교:

Scale-Up (수직 확장)Scale-Out (수평 확장)
방식단일 서버 성능 업그레이드여러 서버 추가
비유더 큰 컴퓨터컴퓨터 여러 대
적합RDBMSNoSQL
한계하드웨어 한계, 비용 ↑데이터 정합성, 네트워크 비용
CPU/RAM/SSD 강화Sharding, Replication

RDBMS가 Scale-Up 선호하는 이유:

  • ACID 일관성 강력 보장 필요
  • JOIN과 트랜잭션 유지 어려움 (분산 환경)
  • 여러 서버에서 JOIN 시 네트워크 비용 폭증

NoSQL이 Scale-Out 선호하는 이유:

  • Sharding(샤딩) 으로 데이터 분할 쉬움
  • BASE 모델 (일관성 일부 포기)
  • JOIN 회피 → 읽기 성능 우선

Replication (복제):

  • Master(쓰기) + Slave(읽기 전용) 구조
  • 대량 읽기 트래픽 분산
  • 그러나 쓰기 트래픽 은 여전히 단일 서버 부담

ILIC의 현실:

  • MySQL 단일 서버 (Scale-Up 가능)
  • 트래픽 증가 시 → Read Replica 추가 (read-only)
  • 더 늘면 → Sharding 검토

자기 점검

  • ILIC의 102개 테이블이 갑자기 5배 커지면? (힌트: Scale-Up 우선, 나중 Replication)
  • 클라우드 환경에서 Scale-Up이 더 쉬워진 이유는? (힌트: 인스턴스 타입 변경)

Unit 5.3 — NoSQL 등장 배경과 4가지 유형

선수 지식: Unit 5.2

RDB의 한계 (NoSQL 등장 동기):
1. 유연한 확장성 부족 (스키마 변경 비용)
2. 데이터 중복 비허용 → 복잡한 JOIN
3. 단일 서버 트래픽 한계
4. ACID 보장의 성능 비용

NoSQL = "Not Only SQL":

  • 비정형 데이터 (예측 불가능한 구조)
  • 대량 분산 데이터에 특화
  • 스키마 없음 또는 느슨한 스키마

NoSQL 5가지 특징:
1. 유연한 스키마 — 무결성 검증을 앱에서 책임
2. 높은 확장성 — Scale-Out 친화
3. 빠른 처리 속도 — JOIN 회피, 중첩 저장
4. 다양한 저장 방식 — JSON, Key-Value, Graph 등
5. BASE 모델 — ACID 대신

4가지 NoSQL 유형 ⭐ :

유형저장 방식대표 제품사용 사례
Key-Value키-값 단순 저장Redis, DynamoDB캐시, 세션
DocumentJSON/BSON 문서MongoDB, CouchDB다양한 구조 데이터
Column-Family열 기반 저장Cassandra, HBase대량 시계열, 분석
Graph노드 + 엣지Neo4j, Amazon Neptune관계 분석, 추천

Document Store 핵심 — 컬렉션(Collection):

  • RDBMS의 테이블과 유사
  • 그러나 고정 스키마 X — 같은 컬렉션 내 다른 구조 문서 저장 가능
// 같은 users 컬렉션 안에 두 다른 구조 OK
{ "name": "Alice", "age": 25 }
{ "name": "Bob", "skills": ["Java", "Python"] }

Graph DB의 강력함:

  • JOIN 없이 엣지로 직접 관계 탐색
  • 친구의 친구의 친구 — RDBMS는 3 JOIN, Graph는 직관적

금융/결제/예약 같은 데이터 일관성 중요 영역은 NoSQL 사용 조심.

자기 점검

  • ILIC의 어떤 데이터를 NoSQL로 옮기면 좋을까? (힌트: 로그, 알림)
  • 한 시스템에 RDBMS와 NoSQL을 함께 쓰는 사례는? (힌트: 폴리글랏 영속성)

Unit 5.4 — Redis

선수 지식: Unit 5.3, 4주차 Phase 5

핵심 개념

Redis (Remote Dictionary Server):

  • Key-Value Store NoSQL의 대표주자
  • 메모리 기반 — 매우 빠름
  • 다양한 타입 지원 (String, List, Set, Hash, Sorted Set, Stream)

활용 영역 ⭐ :

  1. 캐싱 (가장 흔한 사용):
[Client] → [App] → [Redis] (있으면 반환)
                      ↓ (없으면)
                   [DB]  → [Redis 저장] → [Client]
  1. 세션 저장:
  • 분산 환경에서 세션 공유
  • 여러 서버가 같은 Redis 참조
  1. 메시지 큐 (Pub/Sub)

  2. 분산 락:

  • SETNX 명령으로 단일 락 구현
  1. 카운터·랭킹:
  • Sorted Set으로 실시간 랭킹

유튜브 캐싱 예시:
1. 사용자가 동영상 요청
2. Backend → Redis 조회 (TTL 60초 설정)
3. 있으면 → 즉시 반환 (DB 안 거침)
4. 없으면 → DB 조회 → Redis 저장 → 반환

고가용성 (High Availability):

  • Replication
  • Sentinel (감시자) — 자동 failover
  • Cluster — Sharding

ILIC 적용 가능:

  • 운임 코드 마스터 데이터 캐싱
  • 사용자 세션
  • API 요청 제한 (Rate Limiting)

자기 점검

  • Redis가 메모리 기반인데 데이터를 영속화할 수 있는가? (힌트: RDB/AOF)
  • ILIC에 Redis를 도입한다면 어떤 데이터부터? (힌트: 자주 읽고 변경 적은 마스터 데이터)

📚 Phase 6 — 분산 시스템 이론과 락

목표: 데이터베이스의 일관성·가용성 트레이드오프 이론과 동시성 제어를 이해한다.

Unit 6.1 — BASE 모델

선수 지식: Phase 5, 6주차 ACID

핵심 개념

BASE = ACID의 반대 철학 ⭐ :

  • Basically Available
  • Soft state
  • Eventually consistent

3가지 풀어보기:

1. Basically Available (기본적 가용성):

  • 정확한 값을 보장하지 못해도 응답 제공
  • 가용성 우선

2. Soft State (부드러운 상태):

  • 데이터 변경 중 일시적 불일치 허용
  • 일정 시간 후 자동 일관성

3. Eventually Consistent (최종적 일관성):

  • 모든 노드가 항상 동기화 X
  • 언젠가는 일관성 유지

예시 — 분산 환경 게시물 업로드:
1. 사용자가 게시물 업로드
2. 일부 서버: 즉시 반영
3. 일부 서버: 잠시 동안 보이지 않음
4. 몇 초~몇 분 후: 모든 서버 동기화 완료

ACID vs BASE:

측면ACIDBASE
일관성즉시 강한 일관성최종적 일관성
가용성일관성 위해 양보우선 보장
트랜잭션강력느슨
적합 영역금융·결제SNS·로그·검색

자기 점검

  • ILIC가 ACID를 선택한 이유는? (힌트: 운임/예약 정확성 필수)
  • BASE를 채택해도 되는 ILIC 영역은? (힌트: 로그 수집, 알림)

Unit 6.2 — CAP 이론 (CA/CP/AP) ⭐

선수 지식: Unit 6.1

핵심 이론

CAP 이론:

"분산 시스템에서 Consistency, Availability, Partition Tolerance2가지만 만족 가능"

3가지 속성:

정의
C Consistency (일관성)모든 노드에서 같은 값
A Availability (가용성)모든 요청에 응답
P Partition Tolerance (분할 허용성)네트워크 단절 시에도 동작

3가지 조합:

CP (일관성 + 분할 허용성) — NoSQL:

  • 네트워크 장애 시 응답 지연 감수
  • 모든 노드 동기화될 때까지 대기
  • 예: MongoDB, HBase

AP (가용성 + 분할 허용성) — NoSQL:

  • 네트워크 장애 시 일관성 양보
  • 일부 노드 최신 아니어도 즉시 응답
  • 예: Cassandra, DynamoDB

CA (일관성 + 가용성) — RDBMS:

  • 네트워크 장애 무시 (단일 서버)
  • 분산 환경에서는 유지 불가
  • 예: MySQL, PostgreSQL (단일 서버)

중요한 통찰:

"현실 분산 시스템에서는 P(Partition)는 필수"

따라서 진짜 선택은 CP vs AP

ILIC 관점:

  • 단일 MySQL → CA
  • Replica 추가 → 일부 P 고려, 보통 CP
  • 운임 정확성 우선 → 일관성 ↑

자기 점검

  • "CA만 만족하는 분산 시스템이 가능한가?"의 답은? (힌트: NO, 이론적으로 단일 서버만)
  • SNS 서비스의 좋아요 수에 적합한 조합은? (힌트: AP)

Unit 6.3 — PACELC 이론 (CAP의 확장)

선수 지식: Unit 6.2

핵심 개념

CAP의 한계:

  • 네트워크 장애 시만 다룸
  • 정상 상황에서의 트레이드오프는?

PACELC:

"Partition 발생 시 Availability vs Consistency, Else 정상 시 Latency vs Consistency"

두 가지 분기:

PA/PC: 네트워크 장애 시 (CAP과 동일)

  • PA: 가용성 우선
  • PC: 일관성 우선

EL/EC: 정상 시

  • EL: 지연 시간(성능) 우선 → 일관성 양보 가능
  • EC: 일관성 우선 → 응답 시간 양보

대표 시스템 분류:

시스템분류특징
MongoDBPA + EC장애 시 가용성, 정상 시 일관성
CassandraPA + EL장애 시 가용성, 정상 시 지연 우선
HBase, SpannerPC + EC장애 시·정상 시 모두 일관성 우선
DynamoDBPA + ELCassandra 유사
MySQL (단일)(CA), EC장애 가정 X, 일관성

핵심 통찰:

"CAP는 장애 시만 다룬다. PACELC는 평상시 트레이드오프 도 본다"

ILIC 관점:

  • MySQL: EC (일관성 우선) 자연스러움
  • Redis 도입 시: 캐시는 EL (지연 시간 우선)

자기 점검

  • 같은 NoSQL이라도 PACELC 분류가 다른 이유는?
  • 일관성 우선 시 응답 시간이 늘어나는 이유는? (힌트: 다중 노드 합의)

Unit 6.4 — 공유락(S Lock)과 베타락(X Lock)

선수 지식: 4주차 Phase 4 (synchronized), 10주차 Phase 5

핵심 개념

왜 락이 필요한가:

  • 멀티 트랜잭션이 같은 데이터 접근
  • → Race Condition
  • → 데이터 무결성 침해

2가지 락 종류 ⭐ :

공유 락 (Shared Lock, S Lock):

"여러 트랜잭션이 동시에 읽기 OK, 쓰기는 차단"

  • 읽기-읽기 호환
  • 읽기-쓰기 충돌
  • 예: SELECT ... LOCK IN SHARE MODE

베타 락 (Exclusive Lock, X Lock):

"한 트랜잭션만 데이터 접근, 다른 트랜잭션은 읽기조차 차단"

  • 모든 작업과 충돌
  • 가장 강력한 락
  • 예: SELECT ... FOR UPDATE

호환성 매트릭스:

S Lock 요청X Lock 요청
S Lock 보유 중✅ 호환❌ 대기
X Lock 보유 중❌ 대기❌ 대기

JPA에서의 활용 (참고):

@Lock(LockModeType.PESSIMISTIC_READ)  // S Lock
@Lock(LockModeType.PESSIMISTIC_WRITE) // X Lock

격리 수준과의 관계 (10주차 Phase 5):

  • READ COMMITTED: 짧은 S Lock
  • REPEATABLE READ: 긴 S Lock 또는 MVCC
  • SERIALIZABLE: 매우 엄격한 락

ILIC 시나리오:

  • 운임 견적 동시 수정 방지 → X Lock
  • 통계 보고 중 데이터 변경 방지 → S Lock

자기 점검

  • 데드락이 발생하는 시나리오는? (힌트: 두 트랜잭션이 서로의 락 대기)
  • 비관적 락 vs 낙관적 락의 차이는? (힌트: 락 시점)

⚡ Part B — SQL 성능 최적화

📚 Phase 7 — 옵티마이저

목표: SQL이 어떻게 실행 계획으로 변환되는지 — DB의 두뇌를 이해한다.

Unit 7.1 — 옵티마이저 개념 + RBO vs CBO

선수 지식: Unit 5.1

핵심 정의

옵티마이저(Optimizer):

"SQL의 가장 효율적인 실행 경로를 생성하는 DBMS의 핵심 엔진"

비유:

"CPU가 컴퓨터의 두뇌라면, 옵티마이저는 DB의 두뇌"

동작 흐름:
1. 개발자가 SQL 작성
2. 옵티마이저: "이 쿼리를 어떻게 실행할까?"
3. 여러 실행 계획 생성
4. 각 계획의 비용 산정
5. 최저 비용 계획 선택
6. SQL 엔진이 실제 실행


2가지 옵티마이저 종류:

RBO (Rule-Based Optimizer) — 규칙 기반:

  • 사전 정의된 규칙의 우선순위로 결정
  • 통계 정보 사용 안 함
  • Oracle 8 이전 기본
  • 장점: 결과 예측 쉬움
  • 단점: 데이터 분포 무시 → 비효율 가능

CBO (Cost-Based Optimizer) — 비용 기반 ⭐ :

  • 테이블/인덱스/컬럼 통계 활용
  • 비용을 계산해 최저 선택
  • 현대 DBMS의 표준 (MySQL, PostgreSQL, Oracle)
  • 장점: 데이터 분포 고려
  • 단점: 통계 정보가 잘못되면 잘못된 선택

자기 점검

  • 옵티마이저가 항상 최적을 선택하는가? (힌트: NO — 통계 부정확 시)
  • RBO에서 인덱스를 거는 동기는? (힌트: 우선순위에 인덱스 사용이 높음)

Unit 7.2 — 옵티마이저 동작 6단계 + 통계정보

선수 지식: Unit 7.1

핵심 6단계 ⭐ :

[SQL 입력]
    ↓
1. Parser           — SQL 문법 검사 + 파싱 트리 생성
    ↓
2. Query Transformer — 서브쿼리 → JOIN, 불필요 조건 제거
    ↓
3. Estimator        — 실행 비용 계산 (통계 기반)
    ↓
4. Plan Generator   — 실행 계획 후보 생성 + 최적 선택
    ↓
5. Row-Source Generator — 실행 가능한 코드로 변환
    ↓
6. SQL Engine       — 실제 실행
    ↓
[결과 반환]

Step 2 예시 — 쿼리 변환:

-- 입력
SELECT name FROM employees 
WHERE department_id IN (SELECT department_id FROM departments WHERE location = 'Seoul');

-- 옵티마이저가 변환
SELECT e.name FROM employees e
JOIN departments d ON e.department_id = d.department_id
WHERE d.location = 'Seoul';

Step 3 — Estimator의 고려 요소:
1. 인덱스 존재 여부
2. 테이블 크기
3. 조인 방식 (Nested Loop, Hash Join, Merge Join)
4. 정렬 비용


통계 정보(Statistics):

  • 옵티마이저의 핵심 입력
  • 예: 테이블 행 수, 컬럼 분포, 인덱스 카디널리티

갱신 방법:
1. 자동 갱신: DBMS 스케줄러
2. 수동 갱신: 대량 데이터 변경 후 즉시

ANALYZE TABLE employees;

통계가 오래된 경우:

  • 옵티마이저의 잘못된 선택
  • 인덱스 무시, Full Scan 등
  • 수동 ANALYZE 명령 필요

자기 점검

  • ILIC가 1억 건 INSERT 후 실행 계획이 이상하다면? (힌트: ANALYZE TABLE)
  • 인덱스 통계가 잘못되면 어떤 사고? (힌트: 좋은 인덱스 두고 Full Scan)

Unit 7.3 — 옵티마이저 힌트 + 옵티마이저 모드

선수 지식: Unit 7.2

옵티마이저 힌트:

"SQL 안에 주석 형태로 옵티마이저 동작 강제"

문법 (Oracle/MySQL 차이 있음):

SELECT /*+ HINT_NAME(table_name) */ * FROM table_name;

주요 힌트 ⭐ :

힌트의미
/*+ FULL(t) */Full Table Scan 강제
/*+ INDEX(t idx) */특정 인덱스 사용 강제
/*+ ORDERED */FROM 절 순서대로 조인
/*+ USE_HASH(t) */Hash Join 사용
/*+ PARALLEL(t, 4) */병렬 처리

예시:

SELECT /*+ INDEX(emp idx_emp_name) */ *
FROM employees emp
WHERE name = 'John';

옵티마이저 모드:

"옵티마이저의 기본 정책 설정 — 전체 또는 세션 단위"

모드 종류:

모드의미
CHOOSE통계 있으면 CBO, 없으면 RBO (구식)
FIRST_ROWS첫 결과 빠르게 (인터랙티브 UI)
FIRST_ROWS(n)처음 n개 행 빠르게
ALL_ROWS전체 결과 빠르게 (배치 처리, Oracle 10g+ 기본)

힌트 vs 모드:

  • 힌트: 특정 SQL 내에서
  • 모드: 세션/시스템 전체

ILIC 적용 가능:

  • 운임 검색 첫 페이지: FIRST_ROWS
  • 일별 통계 배치: ALL_ROWS
  • 특정 쿼리만 인덱스 강제: 힌트

자기 점검

  • 옵티마이저 힌트를 남용하면 어떤 문제? (힌트: 데이터 변화에 따른 비효율)
  • ILIC 운임 목록 페이징에 어떤 모드가 적합? (힌트: FIRST_ROWS)

📚 Phase 8 — 인덱스 기초 (★ 정점)

목표: DB 성능의 핵심인 인덱스를 빅오 표기법부터 B-tree 구조까지 깊이 이해한다.

Unit 8.1 — 빅오 표기법과 logN

선수 지식: 자료구조 일반 지식

핵심 개념

빅오 표기법:

"알고리즘의 시간 복잡도 — 입력 크기 N에 따른 연산 횟수"

주요 복잡도:

표기의미
O(1)상수 — 입력 무관HashMap.get()
O(logN)로그 — 절반씩 줄임이진 탐색, B-tree
O(N)선형 — 비례Full Scan
O(N²)제곱 — 중첩 반복Nested Loop

logN의 직관:

  • "N을 몇 번 절반으로 줄여야 1이 되는가"

숫자 비교 (N = 100):

  • O(N) = 100
  • O(logN) = log₂100 ≈ 6.64 (2⁶ = 64, 2⁷ = 128)
  • → 약 15배 빠름

N = 1,000,000 (백만):

  • O(N) = 1,000,000
  • O(logN) ≈ 20
  • 5만 배 빠름

핵심 통찰:

"큰 N일수록 logN의 위력이 폭발적"

→ 인덱스가 데이터가 많을 때 더 효과적인 이유.

자기 점검

  • O(NlogN)은 어떤 알고리즘에서 자주 등장? (힌트: 정렬)
  • ILIC의 1만 건 vs 100만 건 테이블에서 인덱스 효과 차이는?

Unit 8.2 — 인덱스 정의와 사용 방법

선수 지식: Unit 8.1

핵심 개념

인덱스(Index):

"검색 성능을 위한 자료구조 — 책의 목차 같은 역할"

Full Scan vs Index:

  • Full Scan: O(N) — 100만 건이면 100만 번 비교
  • B-tree Index: O(logN) — 100만 건도 약 20번 비교

인덱스가 없을 때:

SELECT * FROM users WHERE first_name = 'Minsoo';
-- → 100만 행 전체 비교 (Full Scan)

인덱스가 있을 때:

CREATE INDEX idx_first_name ON users(first_name);
-- → 인덱스 트리에서 약 20번 비교 → 실제 행 위치 확인

왜 인덱스를 쓰는가 (2가지 이유):
1. WHERE 조건 빠른 검색
2. 정렬(ORDER BY)/그룹핑(GROUP BY) 가속

인덱스 생성 문법:

일반 인덱스:

CREATE INDEX player_name_idx ON player(name);
--           ↑ 인덱스 이름           ↑ 컬럼

유니크 인덱스 (멀티 컬럼 = 복합 인덱스):

CREATE UNIQUE INDEX team_id_backnumber_idx 
ON player (team_id, backnumber);

테이블 생성 시:

CREATE TABLE player (
    id BIGINT PRIMARY KEY AUTO_INCREMENT,
    name VARCHAR(100),
    INDEX idx_name (name)
);

Primary Key는 자동 인덱스.

인덱스 정보 확인:

SHOW INDEX FROM player;

Seq_in_index 컬럼:

  • 1, 2 → 멀티컬럼 인덱스의 컬럼 순서

자기 점검

  • ILIC의 어떤 컬럼에 인덱스가 필요할까? (힌트: WHERE/JOIN/ORDER BY 자주 사용)
  • 인덱스가 없는 검색이 1초 → 인덱스 추가 후 어떻게 변할까?

Unit 8.3 — B-tree 인덱스 동작 방식 ⭐⭐⭐

선수 지식: Unit 8.2

핵심 개념

B-tree 인덱스의 본질:

"정렬된 별도 테이블 + 포인터 — 이진 탐색으로 O(logN)"

구조 시각화:

[원본 테이블]                      [인덱스 테이블 (정렬됨)]
+----+----+----+                   +----+----------+
| id | a  | b  |                   | a  | pointer  |
+----+----+----+                   +----+----------+
| 1  | 5  | 80 |                   | 1  | → row 7  |
| 2  | 3  | 60 |                   | 2  | → row 9  |
| 3  | 8  | 95 |        ←CREATE→   | 3  | → row 2  |
| 4  | 1  | 30 |        INDEX(a)   | 5  | → row 1  |
| 5  | 9  | 70 |                   | 6  | → row 8  |
| 6  | 2  | 40 |                   | 8  | → row 3  |
| 7  | 1  | 20 |                   | 9  | → row 5  |
+----+----+----+                   +----+----------+

조회 흐름 (WHERE a = 9):
1. 인덱스 테이블에서 이진 탐색으로 a=9 찾기 (O(logN))
2. 포인터 따라 원본 테이블 row 5 접근
3. → 해당 행 반환


멀티컬럼 인덱스 (Multi-column Index) ⭐ :

CREATE INDEX idx_a_b ON table(a, b);

정렬 기준:
1. a 컬럼 오름차순
2. a 같은 값들 안에서 b 오름차순

예시:

a | b
--+----
1 | 20    ← a 정렬 후
1 | 95
3 | 60
5 | 80
7 | 80
7 | 95   ← 같은 a=7 안에서 b로 정렬
8 | 95
9 | 70

효율적 사용 — WHERE a=7 AND b=95:
1. 인덱스에서 a=7 영역 탐색 (이진)
2. 그 안에서 b=95 탐색 (이진 — 이미 정렬됨)
3. → 완전히 효율적!

비효율 사용 — WHERE b=95:

  • 인덱스가 a로 먼저 정렬됨
  • b만으로는 인덱스가 분산됨
  • Full Scan과 다를 바 없음

비효율 사용 — WHERE a=7 OR c=400:

  • a 인덱스 활용 OK
  • c는 인덱스 없음
  • → c 부분에서 Full Scan ❌

핵심 원칙 ⭐ :

"왼쪽 컬럼 우선 — 멀티컬럼 인덱스는 왼쪽부터 활용 가능한 쿼리에만 효과"

ILIC 적용:

  • WHERE booking_date AND status 자주 → INDEX(booking_date, status)
  • 그러나 WHERE status 만 자주 → INDEX(status) 별도 필요

자기 점검

  • (a, b) 인덱스로 WHERE a > 5 는 효과적인가? (힌트: YES)
  • (a, b) 인덱스로 WHERE a > 5 AND b = 80 는? (힌트: a까지만 — b는 정렬 안 됨)
  • 카디널리티가 낮은 컬럼에 인덱스가 무의미한 이유는? (힌트: 분기점이 적음)

📚 Phase 9 — 멀티컬럼 인덱스와 EXPLAIN

목표: 실행 계획을 직접 분석하고 인덱스 선택을 제어한다.

Unit 9.1 — 여러 인덱스 중 어떤 것이 사용되는가

선수 지식: Phase 8

핵심 시나리오

ILIC player 테이블에 여러 인덱스 존재:

  • (id) — Primary Key 자동
  • (name)
  • (team_id, backnumber)
  • (backnumber)

쿼리:

SELECT * FROM player WHERE backnumber = 7;

의문:

  • (team_id, backnumber)(backnumber) 중 어떤 인덱스 사용?

: 옵티마이저가 결정

일반적 선택:

  • 단독 컬럼 검색 → 단일 인덱스 (backnumber) 선호
  • 그러나 통계에 따라 다를 수도

확인 방법:

EXPLAIN SELECT * FROM player WHERE backnumber = 7;

key 컬럼에 사용된 인덱스 표시

자기 점검

  • 같은 컬럼에 두 인덱스가 있는 게 좋은 설계인가? (힌트: 보통 NO — 중복)
  • (team_id, backnumber) 가 있는데 (backnumber) 가 추가로 필요한 이유는?

Unit 9.2 — EXPLAIN으로 실행 계획 분석 ⭐

선수 지식: Unit 9.1

핵심 개념

EXPLAIN:

"SQL의 실행 계획을 미리 보여주는 명령"

MySQL 출력 주요 컬럼:

컬럼의미
idSELECT 실행 순서
select_typeSIMPLE, SUBQUERY, UNION 등
table대상 테이블
type접근 방식 (가장 중요!)
possible_keys사용 가능한 인덱스들
key실제 사용된 인덱스
key_len인덱스 사용 길이
ref비교 대상
rows검사 예상 행 수
Extra추가 정보 (Using index, filesort 등)

type 컬럼 — 가장 중요 ⭐ :

좋은 순 → 나쁜 순:

type의미평가
constPK/UNIQUE로 1행⭐⭐⭐
eq_refUNIQUE JOIN⭐⭐⭐
ref인덱스 비유니크 일치⭐⭐
range인덱스 범위 검색⭐⭐
index인덱스 풀 스캔
ALL테이블 풀 스캔위험

Extra 컬럼 주요 값:

  • Using index — Covering Index (Phase 10)
  • Using where — WHERE 조건 적용
  • Using filesort — 별도 정렬 (성능 ↓)
  • Using temporary — 임시 테이블 (성능 ↓)

ILIC 활용:

EXPLAIN SELECT * FROM bookings WHERE customer_id = ?;
-- type = ref → 인덱스 사용 ✅
-- type = ALL → Full Scan ❌ → 인덱스 추가 검토

자기 점검

  • Using filesort가 보이면 어떻게 해결? (힌트: ORDER BY 컬럼에 인덱스)
  • type = ALL 이지만 데이터가 적어 빠른 경우는? (힌트: 카디널리티 낮음)

Unit 9.3 — 인덱스 힌트 (USE/FORCE/IGNORE)

선수 지식: Unit 9.2, 7.3

핵심 개념

왜 인덱스 힌트?:

  • 옵티마이저가 잘못된 인덱스 선택 시
  • 통계 정보가 부정확할 때
  • 특정 쿼리만 강제할 때

3가지 힌트 ⭐ :

1. USE INDEX — 사용 유도 (느슨):

SELECT * FROM player USE INDEX (backnumber_idx) 
WHERE backnumber = 7;
  • 옵티마이저가 우선 검토하지만 반드시 사용 X

2. FORCE INDEX — 강제 사용 (강함) ⭐ :

SELECT * FROM player FORCE INDEX (backnumber_idx) 
WHERE backnumber = 7;
  • 반드시 사용
  • USE INDEX보다 강한 제약

3. IGNORE INDEX — 무시 강제:

SELECT * FROM employees IGNORE INDEX (idx_emp_name) 
WHERE name = 'John';
  • 해당 인덱스 사용 안 함
  • 다른 인덱스 또는 Full Scan

언제 사용하는가:

  • 옵티마이저가 잘못된 인덱스 선택 (드물지만)
  • 통계 정보 갱신 직후 검증
  • A/B 테스트로 성능 비교

⚠️ 남용 주의:

  • 데이터 분포가 변하면 잘못된 강제 → 성능 ↓
  • 우선 ANALYZE TABLE 로 통계 갱신 시도

옵티마이저 힌트 vs 인덱스 힌트 (비교):

옵티마이저 힌트인덱스 힌트
범위실행 계획 전체인덱스 사용만
/*+ ORDERED */FORCE INDEX (...)
강제력옵티마이저가 무시 가능FORCE는 강제
표기주석 (/*+ ... */)키워드 (USE/FORCE/IGNORE)

ILIC 활용:

  • 운임 검색 통계가 어쩌다 잘못되어도 정상 운영 보장 → 핵심 쿼리에 FORCE INDEX

자기 점검

  • 인덱스 힌트가 표준 SQL인가? (힌트: NO — DBMS마다 다름)
  • 인덱스 힌트를 운영 코드에 둘 때 위험은? (힌트: 데이터 변화 추적 어려움)

📚 Phase 10 — 인덱스 최적화 전략

목표: 실무 인덱스 설계의 베스트 프랙티스 — 무엇을 할까, 무엇을 피할까.

Unit 10.1 — Covering Index ⭐

선수 지식: Phase 9

핵심 개념

Covering Index:

"쿼리가 필요한 모든 컬럼을 인덱스가 포함하는 경우"

예시:

인덱스: (team_id, backnumber)

SELECT team_id, backnumber FROM player WHERE team_id = 1;

→ 조회 컬럼(team_id, backnumber) 모두 인덱스에 포함
실제 테이블 접근 불필요
인덱스만으로 결과 반환 = Covering Index

장점:

  • 디스크 I/O 절감 (테이블 데이터 페이지 안 읽음)
  • 매우 빠른 조회

EXPLAIN 결과:

  • Extra 컬럼에 Using index 표시

Non-Covering 사례:

SELECT * FROM player WHERE team_id = 1;
-- '*' = 모든 컬럼 → 인덱스 외 컬럼도 필요 → 테이블 접근

Covering 만들기 — 인덱스 확장:

-- 자주 SELECT name도 한다면
CREATE INDEX idx_team_back_name ON player(team_id, backnumber, name);

ILIC 활용:

  • 운임 목록 페이지: (status, created_date, fare_id) 인덱스
  • 자주 조회되는 컬럼들을 함께 묶기

⚠️ 주의:

  • 인덱스가 너무 길면 저장/유지 비용 ↑
  • 적절한 균형 필요

자기 점검

  • SELECT * 가 Covering Index를 깨는 이유는?
  • ILIC의 어떤 빈번 쿼리를 Covering Index로 최적화할 수 있을까?

Unit 10.2 — 인덱스 vs Full Scan 선택 + 주의사항

선수 지식: Unit 10.1

핵심 개념

Full Scan이 더 좋은 경우:

  1. 데이터가 적은 테이블 (몇십~몇백 건)

    • 인덱스 트리 탐색 + 테이블 접근 비용
    • vs 직접 모든 행 읽기
    • → 차이 미미
  2. 조회 데이터가 테이블의 큰 비율 (예: 30% 이상)

    • 어차피 대부분 행 접근
    • 인덱스로 우회하면 이중 비용
    • → Full Scan이 빠름
  3. 카디널리티 매우 낮음

    • 예: status 컬럼 (active/inactive 2개 값)
    • 인덱스 분기 효과 거의 없음

옵티마이저의 판단:

  • 통계 정보 기반으로 자동 결정
  • 30% 이상 → Full Scan 선호 (대략)

인덱스의 비용 ⭐ :

1. WRITE 시 모든 인덱스 갱신:

  • INSERT/UPDATE/DELETE 시 인덱스도 갱신
  • 인덱스 N개 = N번 갱신
  • 불필요한 인덱스가 많으면 쓰기 성능 저하

2. 추가 저장 공간:

  • 인덱스 = 별도 테이블
  • 데이터의 10~30% 추가 공간

3. 인덱스 정렬 비용:

  • 데이터 변경 시 트리 재정렬
  • B-tree 균형 유지 비용

원칙 ⭐ :

"필요한 만큼만, 최소한의 인덱스"

중복 인덱스 피하기:

  • (team_id, backnumber) 있으면 (team_id) 불필요
  • 멀티컬럼이 단일 컬럼을 포함

대용량 테이블 인덱스 추가 주의 ⭐ :

  • 수백만 건 테이블에 인덱스 추가 시 수 분 ~ 수 시간
  • 그동안 DB 성능 저하
  • 트래픽 적은 시간 에 적용
  • 온라인 DDL 사용 (ALGORITHM=INPLACE MySQL 5.6+)

ILIC 시나리오:

  • 운영 중 인덱스 추가 → 새벽 시간
  • 또는 Replica에서 먼저 추가 후 Master 교체 (롤링)

자기 점검

  • ILIC의 일별 통계 테이블에 모든 컬럼에 인덱스를 거는 게 좋은가? (힌트: NO — 쓰기 비용)
  • 인덱스를 안전하게 추가하는 방법은? (힌트: 새벽 + ALGORITHM=INPLACE)

Unit 10.3 — 옵티마이저 힌트 vs 인덱스 힌트 정리

선수 지식: Phase 9, 10

최종 비교 매트릭스 ⭐ :

측면옵티마이저 힌트인덱스 힌트
범위전체 실행 계획 (조인 순서, 병렬 등)인덱스 사용만
표기/*+ ORDERED */ (주석)FORCE INDEX (idx) (키워드)
강제력옵티마이저가 무시 가능FORCE는 거의 절대
표준화DBMS마다 다름DBMS마다 다름
Oracle매우 다양적음
MySQL적음풍부 (USE/FORCE/IGNORE)

힌트 사용 가이드라인:

  1. 우선 ANALYZE TABLE 로 통계 갱신 시도
  2. EXPLAIN 으로 실행 계획 확인
  3. 문제 지속 시 → 힌트 검토
  4. 운영 코드에는 최소한 — 데이터 분포 변화 추적 어려움
  5. 힌트 사용 시 이유를 주석으로 명시

실무 권장 흐름:

[성능 이슈] → ANALYZE TABLE → EXPLAIN → 인덱스 추가 → 힌트
              (1순위)         (분석)     (2순위)      (마지막)

ILIC 적용:

  • 일반 쿼리: 옵티마이저 신뢰
  • 핵심 운영 쿼리: EXPLAIN 정기 점검
  • 통계 의존 우려 쿼리: 힌트 + 주석으로 이유 기록

자기 점검

  • "힌트는 마지막 수단"인 이유는?
  • ILIC에서 인덱스가 50개라면 검토할 것들은? (힌트: 중복, 사용 빈도, 카디널리티)

🎓 종합 자기 점검 (13주차 졸업 시험)

Part A: DB 이론과 관리

DB 용어와 모델링

  1. 엔티티와 릴레이션의 차이를 한 문장씩으로?
  2. 차수와 카디널리티의 차이는?
  3. 도메인의 정의와 사례는?
  4. 스키마 3계층(개념적/논리적/물리적)의 차이는?

정규화

  1. 1NF, 2NF, 3NF, BCNF의 핵심 차이를 한 줄씩으로?
  2. 부분 함수 종속과 이행 함수 종속의 차이는?
  3. BCNF가 3NF보다 더 엄격한 이유는?
  4. 정규화의 단점과 반정규화의 동기는?

이상 현상

  1. 삽입/갱신/삭제 이상 현상을 시나리오로 각각 설명하라
  2. 3가지 이상 현상이 모두 같은 원인에서 비롯되는 이유는?

SQL Injection

  1. SQL Injection의 핵심 원리는?
  2. Prepared Statement가 안전한 이유는?
  3. 다층 방어 5가지를 나열하라

RDBMS와 NoSQL

  1. RDBMS의 4가지 핵심 제약조건은?
  2. Scale-Up과 Scale-Out의 차이와 각자의 적합 영역은?
  3. NoSQL 등장의 4가지 동기는?
  4. NoSQL 4가지 유형을 대표 제품과 함께 설명하라
  5. Redis의 5가지 활용 영역은?

분산 시스템 이론

  1. ACID와 BASE의 철학적 차이는?
  2. CAP 이론의 3가지 속성과 3가지 조합은?
  3. CAP 이론에서 "P는 사실상 필수"인 이유는?
  4. PACELC가 CAP을 어떻게 확장하는가?
  5. 공유락(S)과 베타락(X)의 호환성 매트릭스는?

Part B: SQL 성능 최적화

옵티마이저

  1. RBO와 CBO의 차이는?
  2. 옵티마이저 동작 6단계는?
  3. 통계 정보가 잘못되면 어떤 사고가?
  4. FIRST_ROWS와 ALL_ROWS 모드의 차이는?

인덱스 기초 (★)

  1. logN이 N보다 압도적으로 빠른 이유를 N=백만 사례로 설명하라
  2. B-tree 인덱스가 인덱스 테이블 + 포인터로 동작하는 흐름은?
  3. 멀티컬럼 인덱스 (a, b)에서 WHERE b=... 가 비효율적인 이유는?
  4. 멀티컬럼 인덱스의 "왼쪽 컬럼 우선" 원칙을 설명하라

EXPLAIN과 힌트

  1. EXPLAIN의 type 컬럼에서 좋은 값과 나쁜 값은?
  2. Extra 컬럼의 Using filesort 가 의미하는 바와 해결책은?
  3. USE INDEX, FORCE INDEX, IGNORE INDEX의 차이는?

인덱스 최적화

  1. Covering Index의 정의와 EXPLAIN 표시는?
  2. Full Scan이 인덱스보다 좋은 3가지 경우는?
  3. 인덱스가 많을수록 좋지 않은 3가지 이유는?
  4. 운영 중 대용량 테이블에 인덱스를 안전하게 추가하는 방법은?

📌 학습 운영 팁

9-섹션 마스터 프롬프트로 깊이 파야 할 Unit

★★★ 면접·실무 단골 (반드시):

  • Unit 2.2~2.4 — 1NF/2NF/3NF/BCNF
  • Unit 6.2 — CAP 이론
  • Unit 8.3 — B-tree 인덱스 동작 + 멀티컬럼 인덱스
  • Unit 9.2 — EXPLAIN 분석
  • Unit 10.1 — Covering Index

★★ 매우 권장:

  • Unit 3.1 — 3가지 이상 현상
  • Unit 5.3 — NoSQL 4가지 유형
  • Unit 6.4 — 공유락/베타락
  • Unit 7.2 — 옵티마이저 6단계
  • Unit 10.2 — 인덱스 vs Full Scan 선택

Phase별 진도 체크리스트

[ Part A — DB 이론과 관리 ]
[ ] Phase 1 — DB 핵심 용어와 모델링 (Unit 1.1~1.3)
[ ] Phase 2 — 정규화 (Unit 2.1~2.4)
[ ] Phase 3 — 이상 현상과 정규화 평가 (Unit 3.1~3.2)
[ ] Phase 4 — SQL Injection 보안 (Unit 4.1~4.2)
[ ] Phase 5 — RDBMS와 NoSQL (Unit 5.1~5.4)
[ ] Phase 6 — 분산 시스템 이론 + 락 (Unit 6.1~6.4)

[ Part B — SQL 성능 최적화 ]
[ ] Phase 7 — 옵티마이저 (Unit 7.1~7.3)
[ ] Phase 8 — 인덱스 기초 (Unit 8.1~8.3)  ★ 정점
[ ] Phase 9 — 멀티컬럼 인덱스와 EXPLAIN (Unit 9.1~9.3)
[ ] Phase 10 — 인덱스 최적화 전략 (Unit 10.1~10.3)

[ ] 종합 자기 점검 38문항 통과

13주차의 정점 — Phase 8 (인덱스 기초)

왜 정점인가:

  • DB 성능의 90%를 좌우하는 영역
  • 면접에서 가장 자주 등장 (B-tree, 멀티컬럼)
  • 12주차 N+1 문제와도 직결 (fetch join 최적화의 기반)

학습 시 강조점:

  • B-tree의 정렬 + 포인터 구조 시각화
  • "왼쪽 컬럼 우선" 원칙 체화
  • 직접 EXPLAIN 돌려보며 검증

1~13주차 통합 흐름 — DB 본연의 영역으로

12주차까지가 자바·Spring·JPA의 위쪽 추상화 였다면, 13주차는 DB 자체의 깊이 로 내려갔다.

영역주차추상화 수준
자바 언어1~3주차가장 높음
동시성·Spring4~5주차높음
Spring DB 접근6~7주차중상
AOP·트랜잭션8~10주차중상
JPA·영속성 컨텍스트11~12주차
DB 펀더멘털13주차 (지금)가장 낮음 (DB 자체)

의의:

  • 그동안 JPA가 가려놓았던 DB의 진짜 동작 을 본다
  • 정규화·인덱스·옵티마이저는 모든 ORM의 기반
  • 이제부터 N+1 문제도, 트랜잭션 격리 수준도 더 깊이 이해 가능

학습 시 주의 — 반드시 직접 실행

이번 주차는 이론만 읽으면 절대 체화되지 않습니다:

  1. Phase 2 (정규화) — 위반/적용 사례를 직접 SQL로 작성
  2. Phase 4 (SQL Injection) — 안전한 환경에서 실제 공격 시도
  3. Phase 5 (NoSQL) — Docker로 MongoDB/Redis 띄우고 실습
  4. Phase 6 (락) — 두 트랜잭션을 동시 실행하며 락 충돌 재현
  5. Phase 8~10 (인덱스)반드시 EXPLAIN 으로 실행 계획 확인

특히 Phase 8 (B-tree)Phase 9 (EXPLAIN) 은 ILIC 실제 데이터베이스에서:

EXPLAIN SELECT * FROM bookings WHERE customer_id = ? AND status = ?;
EXPLAIN ANALYZE ...  -- 실제 시간 측정 (PostgreSQL/MySQL 8.0+)

이런 식으로 직접 검증하세요. 1~2시간 EXPLAIN 다양한 쿼리에 돌려보면 인덱스 감각이 폭발적으로 늘어납니다.


profile
Software Developer

0개의 댓글