01. 데이터베이스: 영구적인 창고 (The Persistent Memory)
"변수는 전원을 끄면 사라지지만, 데이터는 영원해야 합니다."
1. Why: 휘발성(RAM) vs 영속성(Disk)
우리가 파이썬에서 users = [] 리스트를 만들어 데이터를 넣는 건, 컴퓨터의 작업대(RAM)를 쓰는 것입니다. 작업대는 빠르지만, 퇴근할 때(컴퓨터 끌 때) 그 위를 싹 치워야 합니다.
비즈니스에서 고객의 정보가 사라지면 안 되겠죠? 그래서 우리는 금고(Hard Disk)에 장부를 보관해야 합니다. 이 디지털 금고가 바로 데이터베이스(DB)입니다.
| 구분 | RAM (메모리) | Disk (데이터베이스) | 비유 |
|---|---|---|---|
| 특징 | 전원 끄면 삭제됨 | 전원 꺼도 유지됨 | 머릿속 단기 기억 vs 노트 필기 |
| 용도 | 현재 계산 중인 값 | 회원가입 정보, 주문내역 | 요리 도마 vs 냉장고 |
| 속도 | 엄청 빠름 (KTX) | 상대적으로 느림 (자전거) | 변수(Variable) vs 파일(File) |
핵심 용어: 영속성 (Persistence) "전원이 꺼져도 데이터가 사라지지 않고 남아있는 특성"을 개발 용어로 영속성이라고 합니다. DB를 배우는 것은 곧 우리 프로그램에 영속성을 부여하는 과정입니다.
1-5. Where: 데이터베이스의 위치 (Backend의 금고)
데이터베이스는 브라우저(Frontend)가 직접 접근할 수 없습니다. (보안상 매우 위험!) 반드시 우리가 4부에서 만든 API 서버(FastAPI)를 통해서만 대화해야 합니다.
graph LR
Client["💻 브라우저 (React)"] <-->|"1. 요청 (JSON)"| API["👨🍳 API 서버 (FastAPI)"]
API <-->|"2. 조회 (SQL)"| DB[("🗄️ 데이터베이스")]
style API fill:#ff9,stroke:#333,stroke-width:2px
style DB fill:#bbf,stroke:#333,stroke-width:2px
해석: API 서버는 손님의 주문(Request)을 받아 주방(DB)에서 재료를 꺼내오고 요리해서 내주는 쉐프(Chef) 역할을 합니다.
2. What: DB는 '스마트한 엑셀'이다
데이터베이스(RDBMS)는 어렵지 않습니다. 그냥 "규칙이 아주 엄격한 엑셀(Excel)"이라고 생각하면 됩니다.
| 엑셀(Excel) 용어 | DB 용어 | 설명 |
|---|---|---|
| 시트 (Sheet) | 테이블 (Table) | 데이터의 주제 (예: 회원표, 주문표) |
| 열 (Column) | 컬럼 / 필드 | 데이터의 항목 (예: 이름, 나이, 이메일) |
| 행 (Row) | 레코드 (Record) | 실제 데이터 한 줄 (예: 철수의 정보) |
| 주민번호 | PK (Primary Key) | 데이터를 구분하는 고유 번호 (중복 불가) |
그럼 그냥 엑셀 쓰면 안 되나요?
안 됩니다. 엑셀은 100만 명이 동시에 접속하면 터집니다. DB는 100만 명이 동시에 접속해도 끄떡없는 초고성능 엑셀입니다.
🕰️ 잠깐 상식: 데이터 저장소의 진화 (History)
데이터베이스도 시대의 요구에 따라 진화해왔습니다. 우리는 현재 가장 표준적인 2세대(RDBMS)를 배웁니다.
| 세대 | 이름 | 특징 | 대표 선수 | 비유 |
|---|---|---|---|---|
| 1세대 | File System | 단순히 텍스트 파일에 저장. 검색이 느리고 관리가 힘듦. | memo.txt |
종이 서류철 |
| 2세대 | RDBMS (Relational Database Management System) |
[현재 표준] 표(Table) 형태로 정리. 데이터의 정합성(규칙)을 중시. | Oracle, MySQL, SQLite | 잘 정리된 엑셀 |
| 3세대 | NoSQL | 빅데이터 시대. 규칙은 좀 느슨해도, 엄청난 양의 데이터를 빠르게 처리. | MongoDB, Firebase | 자유로운 포스트잇 |
💡 Tip
MySQL은 서버용 RDBMS이고, 우리가 쓸 SQLite는 파일용 RDBMS입니다. 문법(SQL)은 99% 똑같습니다.
3. Speed: 인덱스(Index), 데이터의 '찾아보기'
DB가 엑셀보다 수백 배 빠른 결정적인 이유는 바로 인덱스(Index)에 있습니다.
1) 인덱스란 무엇인가?
우리가 두꺼운 전공 서적에서 특정 단어를 찾을 때, 첫 페이지부터 끝까지 다 읽지 않습니다. 책 뒷부분의 '찾아보기(색인)' 페이지를 보고 해당 내용이 있는 페이지로 바로 건너뛰죠.
- 인덱스가 없을 때 (Full Table Scan): 데이터를 찾기 위해 처음부터 끝까지 모든 행을 다 뒤집니다. (데이터가 1억 개면 1억 번 확인)
- 인덱스가 있을 때 (Index Scan): 정렬된 목차를 보고 데이터가 있는 '주소'로 바로 점프합니다. (데이터가 1억 개라도 단 몇 번만에 찾음)
| ID (Index) | 저장 위치 (Address) |
|---|---|
| ... | ... |
| 1054 | A-Sector-05 |
| 1055 | B-Sector-12 👈 (여기 있네! 점프) |
| 1056 | A-Sector-99 |
2) PK(기본키)와 인덱스의 관계
우리가 테이블을 만들 때 PK(Primary Key)를 설정하면, DB는 자동으로 이 PK를 기준으로 인덱스를 생성합니다.
- 학생 ID(PK)로 검색할 때: 0.001초 만에 찾음 (인덱스 사용)
- 학생 이름(인덱스 없음)으로 검색할 때: 학생 수가 많아질수록 점점 느려짐
3) 인덱스의 빛과 그림자
인덱스는 무조건 많이 만든다고 좋은 게 아닙니다.
| 장점 (PROS) | 단점 (CONS) |
|---|---|
| 조회(SELECT) 속도가 압도적으로 빨라짐. | 용량(Storage)을 추가로 차지함 (목차 페이지가 늘어남). |
| 시스템의 전체적인 성능이 향상됨. | 쓰기/수정(INSERT/UPDATE) 속도가 미세하게 느려짐 (데이터를 넣을 때마다 목차도 업데이트해야 함). |
💡 핵심 정리: 인덱스는 "자주 검색되는 조건(Column)"에 설정하는 것이 핵심입니다. 하지만 너무 남용하면 오히려 저장 공간을 낭비하고 쓰기 성능을 떨어뜨릴 수 있습니다.
4. Design: Class Diagram과 ERD의 관계 (The Mirror)
여러분이 AI에게 코딩을 시킬 때 Class Diagram(설계도)을 그려주던 것 기억나시죠? 데이터베이스 설계도인 ERD (Entity Relationship Diagram)는 Class Diagram과 이란성 쌍둥이입니다.
4-1. 객체 세상 vs 데이터 세상
- Class Diagram: 프로그램 세상의 지도. "데이터도 있고, 동작(함수)도 있다."
- ERD: 창고(DB) 세상의 지도. "오직 데이터만 저장한다."
이 둘은 서로 거울처럼 대응됩니다. Class Diagram에서 '함수'만 빼면 그게 바로 ERD입니다.
classDiagram
direction LR
class Python_Class_User {
+int id
+str name
+str email
+login()
+logout()
}
class DB_Table_User {
+int id_PK
+varchar name
+varchar email
}
note for DB_Table_User "오직 데이터만 저장!\n(No Methods ❌)"
Python_Class_User --|> DB_Table_User : "ORM이 연결 (Mapping)"
4-2. 연결의 마법사: ORM
우리가 파이썬으로 Class를 잘 설계하면, ORM이라는 통역사가 알아서 DB에 Table(ERD)을 만들어줍니다. 즉, "Class 설계를 잘하면 DB 설계는 공짜"입니다.
참고: ORM이 통역사라면, 그가 사용하는 '진짜 언어'는 SQL입니다. 우리는 편하게 파이썬을 쓰지만, DB 내부에서는 SQL이 쉴 새 없이 움직이고 있다는 사실을 기억하세요.
4-3. 핵심 차이: 참조(Reference) vs 외래키(FK)
하지만 이 둘은 '관계를 맺는 방식'에서 아주 중요한 차이가 있습니다.
1) 클래스 세상: "너를 내 안에 담을게" (Reference)
객체 지향 프로그래밍에서는 한 객체가 다른 객체를 직접 참조합니다.
* 특징: Course 클래스 안에 Teacher 객체 자체가 들어갑니다. (self.teacher = Teacher())
* 표현: 굳이 번호(id)를 외우지 않고, 그냥 '그 사람(객체)'을 가리킵니다.
2) 데이터 세상: "너의 번호만 기록할게" (Foreign Key)
데이터베이스는 객체를 통째로 저장할 수 없습니다. 오직 값(Value)만 저장합니다.
* 특징: Course 테이블은 Teacher의 모든 정보를 갖는 대신, 주민번호 격인 teacher_id (FK)만 기록합니다.
* 표현: 이 번호를 통해 나중에 Teacher 테이블에서 정보를 찾아옵니다(JOIN).
3) 비교 표: 설계할 때 주의점
| 구분 | 클래스 다이어그램 (Class) | ERD (Database) |
|---|---|---|
| 핵심 식별자 | 없음 (메모리 주소로 구분) | PK (Primary Key) 필수! |
| 관계 표현 | 객체 변수 (student_list) |
FK (Foreign Key) 필수! |
| N:M 관계 | 리스트나 셋(Set)으로 표현 가능 | 연결 테이블이 반드시 필요 |
💡 핵심: 파이썬 코드에서는 점(
.)을 찍어서 바로 접근하지만, DB에서는 '번호표(FK)'만 가지고 있습니다. ORM이 이 번호표를 보고 실제 객체를 찾아와 주는 것입니다.⚠️ 주의: 참조 무결성 (Reference Integrity) 번호표(FK)는 아무 번호나 적을 수 없습니다. 강사 테이블에 1, 2, 3번 강사만 있는데, 강의 테이블에
teacher_id = 99를 적으려 하면 DB 금고지기가 "그런 사람은 없어!"라며 에러를 냅니다. 이것이 데이터가 꼬이는 것을 막아주는 DB의 강력한 보호막입니다.
5. 우리의 도구: SQLite vs MySQL
우리는 상황에 맞춰 두 가지 도구를 적절히 섞어서 쓸 것입니다.
1) SQLite (가벼운 파일)
"간단한 건 파일로 해결하자!"
- 용도: 혼자 개발할 때, 테스트용, 모바일 앱 내부 저장소.
- 특징: 별도 서버 설치 없이 파일 하나(
db.sqlite3)가 곧 엑셀 파일처럼 작동합니다. 파이썬에 내장되어 있어 간편합니다.
2) MySQL (강력한 서버)
"별도 서버가 필요할 땐 MySQL!"
- 용도: 여러 사용자가 동시에 접속하는 서비스, 대용량 데이터 처리, 실제 배포(Production).
- 특징: 별도의 DB 서버 프로그램(또는 클라우드)을 띄워야 합니다.
작전: 우리는 개발 단계(Local)에서는 간편한 SQLite를 쓰고, 실제 배포(Deploy) 때는 MySQL로 자연스럽게 넘어갈 것입니다. (ORM이 이걸 가능하게 해줍니다!)