API 명세 확정 후 DB 설계(데이터 구조 설계) 단계는 백엔드 품질과 확장성을 좌우하는 핵심이죠.
아래는 실무 기준의 단계별 접근법입니다.
💡 1. API 명세서로부터 요구사항 추출
API 명세가 확정됐다면, 이미 아래 정보가 들어있을 겁니다:
- 엔드포인트 (ex: POST /users, GET /articles/{id})
- 요청/응답 스키마 (request body, response JSON 구조)
- 리소스 간 관계 (ex: 유저 → 게시글 → 댓글)
👉 이 단계의 목표:
“서버가 관리해야 하는 데이터의 종류/관계”를 파악하는 것.
예:
{
"user": {
"id": 1,
"name": "Alice"
},
"posts": [
{
"id": 10,
"title": "Hello",
"authorId": 1
}
]
}
→ 테이블 후보: users, posts
→ 관계: posts.authorId → users.id (1:N 관계)
Q. 경로 변수 {id}
GET /articles/{id} 에서 {id} 는 경로 변수(Path Parameter) 라고 합니다.
즉, URL 안에 변하는 값(식별자) 을 담는 플레이스홀더(placeholder) 에요.
🧩 예시로 설명해볼게요
| 요청 | 의미 |
| GET /articles/1 | ID가 1인 게시글 가져오기 |
| GET /articles/42 | ID가 42인 게시글 가져오기 |
이때 API 명세서에서는 {id}처럼 중괄호로 감싸서 표현합니다.
→ “이 부분은 실제로는 숫자나 문자열 값으로 대체될 거야” 라는 뜻이에요.
📘 용어 정리
| 구분 | 예시 | 설명 |
| Path Parameter (경로 변수) | /articles/{id} | 리소스의 식별자, URL 경로에 포함됨 |
| Query Parameter (쿼리 파라미터) | /articles?author=kim&page=2 | 필터링, 정렬, 페이지네이션 등에 사용 |
| Body Parameter (본문 데이터) | { "title": "새 글", "body": "내용" } | POST/PUT/PATCH 요청 시 전송되는 JSON 데이터 |
🧠 백엔드 코드 예시 (Node.js + Express)
app.get('/articles/:id', (req, res) => {
const articleId = req.params.id; // ← 여기서 :id는 URL의 {id}에 대응
// 예: GET /articles/5 → articleId = '5'
// DB 조회 예시
const article = findArticleById(articleId);
res.json(article);
});
요약하자면
✅ {id}는 URL 안에서 리소스를 구분하기 위한 변수 자리(placeholder)
API 요청 시 실제 값으로 대체돼요.
Q. :id 란?
이 차이를 명확히 이해하면 API 명세서와 실제 코드 구현을 연결하기가 훨씬 쉬워집니다.
✅ 핵심 요약부터
| 표현 | 쓰이는 곳 | 의미 |
| /articles/{id} | API 명세서 (문서에서) | “이 자리에 동적으로 변하는 값이 들어온다”는 표기 규칙 |
| /articles/:id | 백엔드 코드 (실제 서버 라우팅 코드, Express 등) | 실제 서버 라우팅 코드에서 변수를 선언하는 문법 |
즉 —
의미(동적으로 변하는 값 = 변수)는 같지만, 쓰는 맥락이 다릅니다.
🔍 자세히 보면
📄 API 명세서에서 {id}
OpenAPI(Swagger)나 REST API 문서에서는 {} 중괄호로 “이건 변수야”라고 표시합니다.
예:
GET /articles/{id}
→ “URL의 {id} 자리에 실제 글 번호가 들어온다”는 뜻.
요청 예시:
GET /articles/1
GET /articles/123
⚙️ 서버 코드에서 :id
Express, Fastify, NestJS 등 대부분의 Node.js 프레임워크에서는
라우트 경로 안에서 콜론(:) 을 사용해 “이 부분은 변수야” 라고 정의합니다.
app.get('/articles/:id', (req, res) => {
console.log(req.params.id);
});
요청:
GET /articles/5
→ req.params.id === '5'
🔄 요약 비교
| 구분 | 명세서예시 | 코드에서 | 실제 요청 예 |
| 문법 | /articles/{id} | /articles/:id | /articles/10 |
| 목적 | API 문서용 표기 | 서버 라우팅용 문법 | 클라이언트가 호출 |
| 역할 | 변수 위치 표시 | 변수 값 추출 | 실제 값 전달됨 |
💡 비유로 쉽게 말하면
| 구분 | 비유 |
| /articles/{id} | “요리책에서 {재료} 준비하기” — 문서용 표기 |
| /articles/:id | “레시피 코드에서 :ingredient 받아오기” — 실제 구현 |
| /articles/5 | “감자를 실제로 넣는 행위” — 실제 요청 |
Q. req.params.id === 5
req.params.id === 5 안에는 JavaScript 문법과 Express의 개념이 같이 들어 있습니다.
💡 1️⃣ req는 뭐냐면
req는 request 객체예요.
즉, 클라이언트가 보낸 요청(Request) 의 모든 정보를 담고 있는 객체입니다.
서버 코드 예시:
app.get('/articles/:id', (req, res) => {
console.log(req); // 클라이언트 요청에 대한 모든 정보
});
req 안에는 여러 종류의 데이터가 들어 있습니다 👇
| 속성 | 설명 | 예시 |
| req.params | URL 경로 변수 | /articles/:id 에서 :id |
| req.query | 쿼리스트링 | /articles?id=5&page=2 |
| req.body | POST/PUT의 JSON 데이터 | { "title": "Hello" } |
| req.headers | 요청 헤더들 | Authorization, Content-Type 등 |
💡 2️⃣ params는 뭐냐면
params는 path parameter(경로 변수)들을 담고 있는 **객체(Object)**입니다.
app.get('/articles/:id')
예를 들어 이런 요청이 들어오면:
GET /articles/5
라우터가 이렇게 되어 있다면:
app.get('/articles/:id', (req, res) => {
console.log(req.params);
});
출력 결과:
{ id: '5' }
즉,
- req.params → { id: '5' } (params = 객체 => 객체로 반환)
- req.params.id → '5' (문자열 타입)
💡 3️⃣ ===는 뭐냐면
===는 자바스크립트의 “엄격한 비교 연산자(strict equality operator)” 입니다.
| 연산자 | 이름 | 설명 |
| == | 느슨한 비교(loose equality) | 타입을 자동으로 변환해서 비교 |
| === | 엄격한 비교(strict equality) | 값과 타입이 모두 같아야 true |
예시:
'5' == 5 // true (문자열이 자동으로 숫자로 변환)
'5' === 5 // false (타입이 다름: string vs number)
5 === 5 // true
💡 4️⃣ 그래서 req.params.id === 5는…
이건 “URL 경로에서 받은 id가 숫자 5와 같은가?”를 확인하는 코드예요.
그런데! req.params.id는 문자열이기 때문에 ===로 비교하면 false가 됩니다.
예:
req.params.id === 5 // false ('5' !== 5)
req.params.id == 5 // true (자동 변환돼서)
실제로 비교하려면 타입 변환을 해주는 게 좋습니다:
Number(req.params.id) === 5 // true
✅ 정리
| 항목 | 설명 | 예시 |
| req | 요청(request) 객체 | 모든 요청 정보 |
| req.params | 경로 변수 객체 | { id: '5' } |
| req.params.id | '5' (문자열) | 경로의 실제 값 |
| === | 엄격한 비교 연산자 | 값 + 타입 모두 비교 |
Q. Number()
이제 JavaScript에서 아주 기본적이면서도 매우 자주 쓰이는 내장 함수 Number()에 대해 정리해볼게요.
💡 Number()란?
Number()는 JavaScript의 내장 함수로,
다른 자료형(문자열, 불리언 등) 을 -> 숫자(Number 타입) 으로 변환(conversion) 해주는 함수입니다.
즉,
👉 “이 값을 숫자로 바꿔줘”
라고 할 때 사용하는 거예요.
🧩 기본 문법
Number(값)
반환: 숫자형(Number)
🔍 예제 살펴보기
1️⃣ 문자열 → 숫자
Number('5') // 5
Number('42.3') // 42.3
Number('0') // 0
Number('abc') // NaN (숫자로 변환 불가)
📘 NaN = “Not a Number” (숫자가 아님을 의미하는 특별한 값)
2️⃣ 불리언 → 숫자 (1, 0)
Number(true) // 1
Number(false) // 0
3️⃣ null / undefined → 숫자 (0, NaN)
Number(null) // 0
Number(undefined) // NaN
4️⃣ 혼합 예시 (공백, ' ', '숫자+영어')
Number(' 123 ') // 123 (공백 무시)
Number('') // 0
Number('12a') // NaN
💡 실무에서 자주 쓰는 이유
예를 들어 Express에서:
app.get('/articles/:id', (req, res) => {
console.log(typeof req.params.id); // 'string'
const id = Number(req.params.id); // 문자열 → 숫자 변환
console.log(typeof id); // 'number'
});
💬 즉,
URL에서 받은 값('5')은 문자열이라 숫자 비교나 계산을 하려면 Number()로 변환해야 합니다.
⚠️ 주의할 점
| 상황 | 결과 | 설명 |
| Number('123abc') | NaN | 숫자+문자 섞이면 변환 실패 |
| Number('') | 0 | 빈 문자열은 0으로 처리 |
| Number(true) | 1 | 불리언은 1/0으로 변환 |
| Number(undefined) | NaN | 변환 불가능 |
🧠 참고: 숫자로 바꾸는 다른 방법들
| 방법 | 예시 | 설명 |
| Number() | Number('5') | 명시적 변환 (가장 안전) |
| parseInt() | parseInt('5px') → 5 | 문자열에서 숫자 부분만 추출 |
| + (단항 연산자) | +'5' → 5 | 짧게 쓰는 방법 |
| parseFloat() | parseFloat('3.14') → 3.14 | 소수점 포함 숫자 변환 |
✅ 요약
- Number()는 값을 숫자형으로 변환하는 내장 함수
- 변환이 불가능하면 NaN 반환
- 문자열로 받은 숫자('5')를 실제 숫자(5)로 바꾸는 데 자주 사용됨
Q. 스키마(Schema)?
이 질문은 API를 설계하거나 백엔드를 구현할 때 핵심 개념을 정확히 짚은 거예요.
이제 “스키마(schema)”가 무엇을 의미하는지 쉽게, 그리고 실무 관점에서 정리해볼게요.
💡 한 줄 정의
스키마(Schema) = 데이터의 구조(Structure) 를 정의한 “설계도”
즉, “이 API에서 어떤 데이터가 오고, 어떤 데이터가 나가는지”를 명확히 표현한 형식이에요.
🧩 요청(Request) 스키마 vs 응답(Response) 스키마
| 구분 | 설명 | 예시 |
| 요청 스키마 (Request Schema) | 클라이언트가 서버로 보내는 데이터 구조 | 회원가입 시 body에 포함되는 JSON |
| 응답 스키마 (Response Schema) | 서버가 클라이언트에게 돌려주는 데이터 구조 | 등록된 유저 정보 JSON |
📘 예시로 이해하기
🔸 API 명세
POST /users
🔹 요청(Request) 스키마
사용자가 회원가입할 때 보내는 데이터 구조
{
"name": "Alice",
"email": "alice@example.com",
"password": "1234"
}
➡️ 이게 “요청 스키마”예요.
서버는 이 구조에 맞는 데이터를 기대합니다.
🔹 응답(Response) 스키마
서버가 회원가입이 끝난 뒤 돌려주는 데이터 구조
{
"id": 1,
"name": "Alice",
"email": "alice@example.com",
"created_at": "2025-10-09T12:34:56Z"
}
➡️ 이게 “응답 스키마”예요.
서버가 반환할 JSON 구조를 약속하는 거죠.
🧠 비유로 이해하기
| 개념 | 비유 |
| 요청 스키마 | “요리 재료 목록” — 요리를 시작하려면 재료가 맞아야 함 |
| 응답 스키마 | “요리 결과물의 형태” — 만들어서 돌려주는 완성품 형태 |
| 스키마 자체 | “요리 레시피의 설계도” — 어떤 재료와 순서로 구성되는지 설명 |
⚙️ 실무에서는 이렇게 사용돼요
예를 들어 OpenAPI (Swagger) 문서에서는 이런 식으로 정의합니다 👇
paths:
/users:
post:
requestBody:
content:
application/json:
schema:
type: object
properties:
name:
type: string
email:
type: string
password:
type: string
required: [name, email, password]
responses:
'201':
description: Created
content:
application/json:
schema:
type: object
properties:
id:
type: integer
name:
type: string
email:
type: string
💬 여기서 schema가 바로 JSON 데이터 구조를 정의하는 부분이에요.
✅ 요약 정리
| 구분 | 의미 | 예시 |
| 스키마(schema) | 데이터의 구조/형식/규칙 정의 | JSON, DB, API 등 어디서든 사용 |
| 요청 스키마 | 클라이언트 → 서버로 보내는 데이터 구조 | { "name": "Alice" } |
| 응답 스키마 | 서버 → 클라이언트로 보내는 데이터 구조 | { "id": 1, "name": "Alice" } |
Q. type: integer (responses - id)
type: integer에서 integer(인트저) 가 뭔지 이해하면, 데이터 타입(type) 개념이 완전히 잡힙니다.
💡 한 줄 정의
integer(정수) = 소수점이 없는 숫자
예: -3, 0, 42, 99999
📘 예시로 비교해볼게요
| 값 | 타입 | 설명 |
| 42 | ✅ integer | 정수 (소수점 없음) |
| 3.14 | ❌ number (실수) | 소수점 있음 |
| -10 | ✅ integer | 음의 정수 |
| "42" | ❌ string | 문자열, |
| 0 | ✅ integer | 정수 |
🧩 스키마에서의 의미 (type: integer)
API 명세서나 JSON Schema에서
type: integer
라고 하면,
그 필드는 반드시 정수만 들어와야 한다는 뜻이에요.
예시:
properties:
id:
type: integer
name:
type: string
→ 이 말은
- id는 숫자(정수)여야 하고,
- name은 문자열이어야 한다는 뜻이에요.
🧠 비교: integer vs number
| integer | 정수만 허용 | 1, 0, -42 |
| number | 정수 + 소수 둘 다 허용 (실수) | 1, 0.5, 3.14 |
예시:
age:
type: integer # 25 (✅), 25.5 (❌)
rating:
type: number # 4.5 (✅), 5 (✅)
⚙️ 실제 JSON 예시
✅ 유효한 데이터
{
"id": 1,
"price": 19.99
}
❌ 유효하지 않은 데이터 (스키마 위반)
{
"id": "1", // 문자열이라 오류
"price": "19.99" // 문자열이라 오류
}
✅ 요약
| 용어 | 뜻 | 예시 |
| integer | 정수형 데이터 | 1, 0, -100 |
| number | 모든 숫자형 (소수 포함) | 3.14, 42, -1.5 |
| string | 문자형 | "hello", "123" |
| boolean | 참/거짓 | true, false |
Q. schema - type: object ?
핵심은 👉 JSON은 데이터 "표현 형식"이고,
schema: type: object는 데이터의 "구조 정의" 라는 점이에요.
하나씩 정리해드릴게요.
💡 1️⃣ JSON은 “데이터 형식(포맷, format)”이에요
JSON(JavaScript Object Notation)은
데이터를 주고받을 때 쓰는 텍스트 형태의 표현 방식이에요.
예를 들어 아래는 JSON “데이터”죠:
{
"name": "Alice",
"age": 25
}
여기서 중요한 건:
이건 문자열로 된 데이터 표현일 뿐이고,
그 안에는 문자열, 숫자, 객체, 배열 같은 자료형(type) 들이 들어 있습니다.
💡 2️⃣ schema는 “데이터 구조(모양)”를 정의하는 설계도예요
OpenAPI에서 schema는
“이 JSON이 어떤 구조로 되어 있어야 하는가?”를 기술한 설계서(blueprint) 역할을 합니다.
예를 들어 Swagger에서 이렇게 쓴다면 👇
requestBody:
content:
application/json:
schema:
type: object
properties:
name:
type: string
age:
type: integer
이건 다음 의미예요:
“요청 본문은 application/json 타입의 데이터이고,
그 JSON은 객체(object) 형태이며,
그 안에는 name(문자열)과 age(정수)가 있어야 한다.”
즉, 실제 요청 데이터는 이렇게 생긴 JSON이 된다는 뜻이에요 👇
{
"name": "Alice",
"age": 25
}
💡 3️⃣ 왜 type: object라고 하냐면
type: 아래에 들어가는 건 JSON 내부 자료형이에요.
JSON은 다음 6가지 기본 자료형을 가지고 있습니다 👇
| JSON 타입 | 예시 | 설명 |
| object | { "name": "Alice" } | 키-값 쌍의 집합 |
| array | [1, 2, 3] | 값들의 순서 있는 리스트 |
| string | "hello" | 문자열 |
| integer | 5 | 정수 |
| number | 3.14 | 실수 |
| boolean | true | 참/거짓 |
즉,
JSON 자체는 하나의 포맷(문자열 형태)이고,
그 안에 어떤 타입 구조(object/array 등) 를 가지는지를 schema에서 설명하는 거예요.
💡 4️⃣ 비유로 이해하면
| 개념 | 역할 | 비유 |
| JSON | 실제 데이터 파일 | 완성된 도시 |
| schema | 데이터 구조 정의서 | 도시의 설계도 |
| type: object | JSON의 구조(객체 형태) | 도시 안에 건물들이 있는 형태 |
즉,
“이 API는 JSON 데이터를 주고받는다.”
“그 JSON의 구조는 객체 형태다 (type: object).”
두 문장은 전혀 모순되지 않습니다 —
서로 다른 관점에서 데이터를 설명하는 거예요.
💡 5️⃣ 실제로는 이렇게 세 겹으로 표현돼요
requestBody:
content:
application/json: # JSON 포맷 (데이터 형태)
schema: # 구조 정의 (설계도)
type: object # JSON이 객체 형태임
properties:
title:
type: string
content:
type: string
→ application/json : 데이터가 JSON으로 전달된다
→ schema : 그 JSON이 어떤 구조를 가져야 하는지 정의한다
→ type: object : JSON의 루트가 객체이다
✅ 정리
| 구분 | 의미 | 예시 |
| JSON | 데이터 포맷 (전송 형태) | { "name": "Alice" } |
| schema | 데이터 구조 정의 | name은 string, age는 integer |
| type: object | JSON이 “객체” 구조라는 뜻 | { ... } 형태 |
🧩 2. 엔티티(테이블) 도출 및 관계 정의
도출된 리소스를 중심으로 다음을 설계합니다:
| 엔티티 | 설명 | 주요 컬럼 | 관계 |
| users | 사용자 정보 | id, password, name, email | posts(1:N) |
| posts | 게시글 | id, title, body, author_id | users(N:1), comments(1:N) |
| comments | 댓글 | id, content, post_id, author_id | posts(N:1), users(N:1) |
👉 ERD(Entity Relationship Diagram) 도구로 시각화:
- 추천: dbdiagram.io, Draw.io, ERDCloud, Lucidchart
Q. 엔티티 (Entity)
이제 데이터베이스 설계의 핵심 개념인 "엔티티(Entity)" 를 배우시려는 거네요.
이건 정말 중요합니다 — API, ORM, ERD, 모든 데이터 설계의 출발점이에요.
하나씩 단계적으로 정리해드릴게요 👇
💡 1️⃣ 엔티티(Entity)란?
엔티티(Entity) = 데이터베이스에 저장할 가치가 있는 “대상(thing)”
즉, **데이터베이스에 저장해야 하는 실제 세계의 개체(객체)**를 말합니다.
사람, 상품, 주문, 게시글, 댓글 … 이런 것들이 전부 엔티티예요.
예시 1 — 블로그 시스템
| 실제 세상 | DB에서의 엔티티 | 테이블 이름 |
| 사용자 | User | users |
| 게시글 | Article | articles |
| 댓글 | Comment | comments |
즉, 엔티티는 테이블의 추상적 개념이라고 보면 됩니다.
DB에선 엔티티마다 하나의 테이블이 생겨요.
💡 2️⃣ 엔티티의 구성요소
엔티티는 보통 속성(attribute) 들을 가집니다.
→ 테이블로 보면 컬럼(column) 이죠.
예를 들어 User 엔티티를 보면:
| 속성 (컬럽) | 설명 | 예시값 |
| id | 고유 식별자 (Primary Key) | 1 |
| name | 이름 | “Alice” |
| 이메일 주소 | “alice@example.com” | |
| created_at | 가입일 | 2025-10-09 |
→ 이런 속성들이 모여서 하나의 엔티티(=테이블) 를 구성합니다.
💡 3️⃣ 엔티티 간 관계 (Relationship)
현실 세계의 대상들은 서로 관계가 있죠.
DB에서도 엔티티들은 1:1, 1:N, N:M 관계를 가집니다.
| 관계 | 예시 | 설명 |
| 1:1 | 사용자 ↔ 프로필 | 한 사용자당 -> 하나의 프로필 |
| 1:N | 사용자 ↔ 게시글 | 한 사용자가 -> 여러 게시글 작성 |
| N:M | 게시글 ↔ 태그 | 한 게시글에 -> 여러 태그 한 태그가 -> 여러 게시글에 연결 |
이 관계를 시각적으로 표현한 게 바로 ERD (Entity Relationship Diagram) 입니다.
💡 4️⃣ 엔티티 ≠ 객체, 하지만 비슷함
엔티티는 DB 설계 용어이고,
객체(Object) 는 코드(예: JavaScript, Python, Java)에서의 용어지만
둘은 개념적으로 거의 1:1로 대응합니다.
| 개념 | DB | 코드 |
| 엔티티(Entity) | users 테이블 | User 클래스 |
| 속성(Attribute) | 컬럼(column) | 클래스의 필드(field) |
| 관계(Relationship) | 외래키(Foreign Key) | 참조(reference) |
예:
// 코드 (TypeORM 예시)
@Entity()
class User {
@PrimaryGeneratedColumn()
id: number;
@Column()
name: string;
}
이건 결국 DB의 users 엔티티(테이블)에 해당하는 구조예요.
💡 5️⃣ 실무에서 엔티티를 정리하는 방법
보통 이렇게 표로 정리합니다 👇
| 엔티티 | 속성 | 데이터타입 | 제약조건 |
| User | id | INT | PK |
| name | VARCHAR(50) | NOT NULL | |
| VARCHAR(100) | UNIQUE | ||
| Article | id | INT | PK |
| title | VARCHAR(255) | NOT NULL | |
| author_id | INT | FK → User.id |
✅ 요약
| 용어 | 의미 | 예시 |
| 엔티티(Entity) | 저장할 수 있는 "대상" | User, Product, Order |
| 속성(Attribute) | 엔티티의 특징 | name, email, created_at |
| 식별자(Key) | 각 엔티티를 구별하는 값 | id |
| 관계(Relationship) | 엔티티 간의 연결 | 1:N, N:M |
🧠 비유하자면
- 엔티티 → “엑셀 시트”
- 속성(컬럼) → “엑셀의 열(Column)”
- 레코드(인스턴스) → “엑셀의 한 줄(Row)”
Q. TypeORM 이란?
TypeORM은 백엔드 개발에서 정말 자주 쓰이는 개념이에요.
하나씩 쉽게 풀어 설명해드릴게요.
💡 1️⃣ TypeORM이란?
TypeORM = TypeScript/JavaScript용 ORM(Object-Relational Mapping) 라이브러리
즉, 데이터베이스 테이블과 ~ 객체(Object)를 연결해주는 도구입니다.
🔍 핵심 개념
- ORM(Object-Relational Mapping)
DB 테이블을 = **코드 안의 객체(클래스)**로 매핑(mapping)해서 사용 - TypeORM은 TypeScript 친화적 → 타입 안정성 제공
- 다양한 DB 지원: MySQL, PostgreSQL, SQLite, SQL Server 등
💡 2️⃣ 왜 TypeORM을 쓰는가?
| 장점 | 설명 |
| 코드 중심 개발 | SQL 없이 JS/TS 코드만으로 CRUD 가능 |
| 타입 안전성 | TypeScript와 완전히 호환, 컴파일 시 타입 체크 가능 |
| DB 독립성 | MySQL ↔ PostgreSQL ↔ SQLite 쉽게 변경 가능 |
| 마이그레이션 지원 | 테이블 구조 변경 시 스크립트 생성 가능 |
💡 3️⃣ 간단 예시
엔티티 정의
import { Entity, PrimaryGeneratedColumn, Column } from "typeorm";
@Entity() // 이 클래스가 DB 테이블임을 선언
export class User {
@PrimaryGeneratedColumn()
id: number;
@Column()
name: string;
@Column({ unique: true })
email: string;
}
- @Entity() → 테이블 선언
- @PrimaryGeneratedColumn() → 자동 증가 PK
- @Column() → 테이블 컬럼 정의
CRUD 예시
import { getRepository } from "typeorm";
const userRepo = getRepository(User);
// Create
const newUser = userRepo.create({ name: "Alice", email: "alice@example.com" });
await userRepo.save(newUser);
// Read
const user = await userRepo.findOneBy({ id: 1 });
// Update
user.name = "Alice Smith";
await userRepo.save(user);
// Delete
await userRepo.remove(user);
✔ 여기서 한 가지 눈에 띄는 점:
SQL 문을 직접 쓰지 않아도 테이블과 컬럼이 매핑되어 CRUD가 가능하다는 점!
💡 4️⃣ 마이그레이션
TypeORM은 데이터베이스 구조 변경도 지원합니다.
# 새로운 컬럼 추가 시
typeorm migration:generate -n AddAgeToUser
typeorm migration:run
- 기존 테이블 데이터 손실 없이 구조 변경 가능
💡 5️⃣ 요약
| 용어 | 의미 |
| TypeORM | TypeScript용 ORM 라이브러리 |
| ORM | 객체와 DB를 연결해주는 도구 |
| Entity | 테이블과 1:1 매핑되는 클래스 |
| Repository | 엔티티 CRUD 담당 객체 |
| Migration | 테이블 구조 변경 기록 + 적용 |
Q. 외래키 (Foreign Key)
데이터베이스 설계에서 **외래키(Foreign Key, FK)**는 핵심 개념 중 하나입니다.
하나씩 쉽게 풀어드릴게요.
💡 1️⃣ 외래키(Foreign Key)란?
외래키(FK) = 다른 테이블의 기본키(PK)를 참조하는 컬럼
즉, 테이블 간의 연결 고리 역할을 하며,
데이터의 무결성(Integrity) 을 보장합니다.
🔍 비유
- User 테이블 = 사람 명단
- Post 테이블 = 게시글 목록
- 게시글 작성자(Post.author_id) 정보를 Post에 저장할 때 [FK] → User.id를 참조 [PK]
- 이 참조 컬럼이 바로 외래키(FK)
Post.author_id → User.id
💡 2️⃣ 예시 테이블
User 테이블
| id (PK) | name |
| 1 | Alice |
| 2 | Bob |
Post 테이블
| id (PK) | title | author_id (FK) |
| 10 | Hello World | 1 |
| 11 | My Post | 2 |
- author_id 컬럼이 User.id를 참조하는 외래키입니다.
- 의미: 게시글 작성자는 반드시 존재하는 사용자여야 함.
💡 3️⃣ 외래키의 특징
- 참조 무결성 보장
- FK로 연결된 값이 반드시 참조 테이블에 존재해야 함
- 예: Post.author_id = 3 → User 테이블에 id=3이 없으면 오류
- 테이블 관계 표현
- 1:N 관계 → FK가 N 쪽 테이블에 존재
- 예: User(1) ↔ Post(N)
- ON DELETE / ON UPDATE 옵션
- 참조 데이터가 삭제/수정될 때 FK 동작 정의 가능
FOREIGN KEY (author_id) REFERENCES users(id)
ON DELETE CASCADE -- User 삭제 시 관련 Post도 삭제
ON UPDATE CASCADE -- User PK 변경 시 Post.author_id도 자동 변경
💡 4️⃣ SQL 예시
CREATE TABLE users (
id SERIAL PRIMARY KEY,
name VARCHAR(50)
);
CREATE TABLE posts (
id SERIAL PRIMARY KEY,
title VARCHAR(100),
author_id INT,
FOREIGN KEY (author_id) REFERENCES users(id)
);
- posts.author_id가 users.id를 참조
- User 테이블에 없는 값은 들어갈 수 없음
💡 5️⃣ 요약
| 용어 | 의미 | 예시 |
| Primary Key (PK) | 테이블의 고유 식별자 | users.id |
| Foreign Key (FK) | 다른 테이블 PK 참조 | posts.author_id → users.id |
| 참조 무결성 | FK 값은 반드시 참조 테이블에 존재 | author_id=1 → User.id=1 존재 |
Q. 무결성 이란?
데이터베이스에서 말하는 무결성(Integrity) 은 아주 중요한 개념이에요.
쉽게 말하면 데이터가 항상 올바르고 일관되게 유지되는 상태를 의미합니다.
💡 1️⃣ 무결성(Integrity)란?
무결성(Integrity) = 데이터의 정확성, 일관성, 신뢰성을 보장하는 성질
즉,
잘못된 데이터가 들어가지 않도록 하고테이블 간 데이터가 서로 모순되지 않도록 관리하는 것
🔍 2️⃣ 무결성의 종류
① 참조 무결성(Referential Integrity)
- **외래키(Foreign Key)**와 관련
- 한 테이블의 값이 -> 다른 테이블에 반드시 존재해야 함
- 예:
posts.author_id → 반드시 users.id에 존재해야 함
② 개체 무결성(Entity Integrity)
- **기본키(PK)**와 관련
- 테이블의 기본키는 NULL이 될 수 없고, 유일해야 함
- 예:
users.id → 항상 고유, NULL 불가
③ 도메인 무결성(Domain Integrity)
- 컬럼 값의 타입 / 범위 / 형식을 제한
- 예:
age INT CHECK(age >= 0) -- 나이는 0 이상
email VARCHAR(100) -- 최대 100자
- 타입: INT
- 범위: CHECK(age >= 0)
- 형식: VARCHAR(100) -- 최대 100자
- 특정 비즈니스 규칙을 적용
- 예:
- 주문 금액 ≥ 0
- 회원 등급은 “bronze, silver, gold” 중 하나
💡 3️⃣ 비유로 이해하기
- 무결성 없는 데이터 → 엉망진창 엑셀
- 무결성 있는 데이터 → 항상 규칙과 일관성을 지키는 관리된 엑셀
예:
| user_id | post_title | author_id |
| 1 | Hello | 1 |
| 2 | Hi | 3 |
💡 4️⃣ 요약
| 용어 | 설명 | 예시 |
| 무결성(Integrity) | 데이터의 정확성과 일관성 | PK, FK / 컬럼 타입, 범위 제한 |
| 참조 무결성 | FK가 참조 테이블 존재 | posts.author_id → users.id |
| 개체 무결성 | PK는 유일, NULL 불가 | users.id |
| 도메인 무결성 | 컬럼 타입/범위 제한 | age ≥ 0 |
| 사용자 정의 무결성 | 비즈니스 규칙 적용 | 주문 금액 ≥ 0 |
Q. SERIAL / VARCHAR()
SERIAL과 VARCHAR()는 DB 컬럼의 데이터 타입을 정의할 때 사용됩니다. 하나씩 자세히 설명할게요.
💡 1️⃣ SERIAL이란?
SERIAL = 자동 증가 정수형(Integer Auto Increment)
즉, 새로운 레코드가 들어올 때마다 DB가 알아서 1씩 증가시키는 정수 컬럼이에요.
🔍 특징
- 주로 Primary Key로 사용
- 자동으로 고유값 생성 →
따로 값을 넣어줄 필요없음 - PostgreSQL에서 지원하는 타입
📘 예시
CREATE TABLE users (
id SERIAL PRIMARY KEY,
name VARCHAR(50)
);
- 첫 번째 레코드 → id = 1
- 두 번째 레코드 → id = 2
- 세 번째 레코드 → id = 3
- … 자동 증가
💬 MySQL에서는 SERIAL 대신 INT AUTO_INCREMENT를 사용합니다.
💡 2️⃣ VARCHAR(n)이란?
VARCHAR(n) = 가변 길이 문자열(Variable-length Character, 최대 n 글자)
즉, 최대 n글자까지 들어갈 수 있는 텍스트 컬럼입니다.
🔍 특징
- 고정 길이 CHAR보다 공간 효율적
- 문자열 길이에 따라 저장 공간이 달라짐
📘 예시
name VARCHAR(50)
- name 컬럼에 최대 50글자까지 저장 가능
- “Alice” → 5글자 → 필요한 만큼만 저장
- “This is a long name” → 21글자 → 저장 가능
참고: VARCHAR()는 텍스트 길이를 제한할 수 있지만, 너무 작은 값으로 설정하면 긴 문자열 삽입 시 오류 발생
💡 3️⃣ 간단 비교
| 타입 | 설명 | 예시 |
| SERIAL | 자동 증가 정수 | 1, 2, 3 … (주로 PK) |
| VARCHAR(n) | 최대 n글자 가변 문자열 | 'Alice', 'Hello World' |
💡 4️⃣ 예시 테이블
CREATE TABLE users (
id SERIAL PRIMARY KEY, -- 자동 증가 정수
name VARCHAR(50), -- 최대 50글자 문자열
email VARCHAR(100) UNIQUE -- 최대 100글자, 유일
);
- id → 레코드마다 자동 증가하는 고유값
- name → 최대 50글자 이름 저장
- email → 최대 100글자, 중복 불가
Q. id 도 중복되면 안 되잖아. 근데 UNIQUE 안 쓰고, SERIAL 만 쓰는 건, 어차피 1씩 증가되서 중복될 일이 없어서 안 쓰는 거야?
말씀하신 대로 SERIAL 자체만으로는 중복을 막을 수 없지만,
일반적으로 Primary Key(PK)로 사용하면 자동으로 UNIQUE가 적용되기 때문에 따로 UNIQUE를 붙이지 않아도 됩니다.
하나씩 자세히 설명할게요.
💡 1️⃣ SERIAL과 중복
- SERIAL은 자동 증가 정수형이어서 레코드가 들어올 때마다 1씩 증가합니다.
- 예를 들어:
id SERIAL
| 레코드 | id 값 |
| 1 | 1 |
| 2 | 2 |
| 3 | 3 |
- 일반적으로 레코드가 삽입될 때 DB가 자동으로 증가값을 할당
- 하지만, 그냥 SERIAL만 쓰면 UNIQUE/PK 제약이 없기 때문에 수동으로 같은 값 삽입 가능
- 예: INSERT INTO users(id, name) VALUES (2, 'Alice') → 강제로 중복 가능
💡 2️⃣ PRIMARY KEY와 SERIAL
id SERIAL PRIMARY KEY
- PRIMARY KEY를 붙이면 중복 방지 + NULL 불가가 자동 적용됩니다.
- 즉, 자동 증가 + 유일성 + NOT NULL을 동시에 만족
- 그래서 보통 SERIAL을 PK로 사용하면 UNIQUE를 따로 쓰지 않아도 됨
✅ 예시
CREATE TABLE users (
id SERIAL PRIMARY KEY,
name VARCHAR(50)
);
- 첫 번째 레코드 → id=1
- 두 번째 레코드 → id=2
- 중복 삽입 시 DB가 오류 발생 (PK 위반)
💡 3️⃣ 결론
| 컬럼 정의 | 중복 가능? | NULL 가능? | 설명 |
| id SERIAL | ✅ 가능 (강제로 넣으면 중복 가능) | ✅ 가능 | 그냥 숫자 증가만 |
| id SERIAL PRIMARY KEY | ❌ 불가 | ❌ 불가 | 자동 증가 + 유일 + NOT NULL → 보통 이렇게 씀 |
| id SERIAL UNIQUE | ❌ 불가 | ✅ 가능 | 자동 증가 + 유일, PK 아님 |
즉, 중복을 막으려면 PK 또는 UNIQUE를 명시해야 함
그냥 SERIAL만 쓰면 “자동 증가”라는 장점만 있고, 유일성 보장은 제약조건이 없으면 깨질 수 있음
Q. NULL / NOT NULL
데이터베이스에서 NULL과 NOT NULL 개념은 아주 기본적이면서도 핵심이에요.
하나씩 차근차근 설명할게요.
💡 1️⃣ NULL이란?
NULL = 값이 없음, 비어 있음, 정의되지 않음
즉, **“아직 데이터가 존재하지 않는다”**라는 의미예요.
🔍 예시
CREATE TABLE users (
id SERIAL PRIMARY KEY,
name VARCHAR(50) NOT NULL,
email VARCHAR(100)
);
- 여기서 email 컬럼에 아무 값도 안 넣으면 → NULL(값이 없음)
- 의미: Alice의 이메일 정보가 아직 없음
💡 2️⃣ NOT NULL이란?
NOT NULL = 값이 반드시 존재해야 함
즉, 이 컬럼에는 빈 값(NULL)을 넣을 수 없음이라는 제약입니다.
🔍 예시
CREATE TABLE users (
id SERIAL PRIMARY KEY,
name VARCHAR(50) NOT NULL,
email VARCHAR(100)
);
- name 컬럼은 무조건 값이 있어야 함 → 없으면 오류
- email 컬럼은 선택적 → 값 없으면 NULL 가능
INSERT INTO users (name) VALUES ('Alice'); -- OK
INSERT INTO users (name, email) VALUES (NULL, 'alice@example.com'); -- ❌ 오류
💡 3️⃣ NULL과 NOT NULL 비교
| 컬럼 | 설명 | 가능 값 |
| name VARCHAR(50) | 값 없어도 됨 (선택) | 'Alice', NULL |
| name VARCHAR(50) NOT NULL | 값 반드시 존재 (필수) | 'Alice', '' (빈 문자열은 가능), NULL ❌ |
💬 주의: NULL ≠ 빈 문자열('')
NULL → 값이 없음
'' → 값은 존재하지만 길이가 0인 문자열
💡 4️⃣ PK, UNIQUE와 NOT NULL 관계
- Primary Key → 자동으로 NOT NULL + UNIQUE
- Unique 컬럼 → 기본적으로 NULL 허용 가능
- 하지만 데이터 무결성을 위해 보통 NOT NULL 같이 사용
💡 5️⃣ 요약
| 용어 | 의미 | 예시 |
| NULL | 값이 없음 | email = NULL |
| NOT NULL | 값이 반드시 존재해야 함 | name NOT NULL |
| 빈 문자열('') | 값은 있지만, 길이가 0 (문자열) | name = '' |
| PK | 자동 NOT NULL + UNIQUE | id SERIAL PRIMARY KEY |
⚙️ 3. 정규화(및 비정규화 고려)
- 1NF: 컬럼은 원자값만 (리스트 X)
- 2NF: 부분 종속 제거
- 3NF: 이행 종속 제거 (데이터 중복 최소화)
- 비정규화: 조회 성능 필요 시 일부 중복 허용 (ㅠ칼럼 등)
예:
- 댓글 수 카운트를 posts.comment_count로 미리 저장해두는 등
🧠 4. 실제 스키마 설계 (SQL 수준)
예를 들어 PostgreSQL 기준:
CREATE TABLE users (
id SERIAL PRIMARY KEY,
name VARCHAR(50) NOT NULL,
email VARCHAR(100) UNIQUE NOT NULL,
password VARCHAR(255) NOT NULL,
created_at TIMESTAMP DEFAULT NOW()
);
CREATE TABLE posts (
id SERIAL PRIMARY KEY,
title VARCHAR(200) NOT NULL,
body TEXT,
author_id INT REFERENCES users(id),
created_at TIMESTAMP DEFAULT NOW()
);
CREATE TABLE comments (
id SERIAL PRIMARY KEY,
content TEXT NOT NULL,
author_id INT REFERENCES users(id),
post_id INT REFERENCES posts(id),
created_at TIMESTAMP DEFAULT NOW()
);
Q. TIMESTAMP / DEFAULT / NOW()
아주 흔하게 쓰이는 DB 컬럼 정의죠.
created_at TIMESTAMP DEFAULT NOW()를 하나씩 풀어서 설명할게요.
💡 1️⃣ created_at
- 단순히 **컬럼 이름(column name)**입니다.
- 일반적으로 레코드가 생성된 시각을 저장하는 용도로 사용합니다.
- 이름은 자유롭게 바꿀 수 있지만, 관례적으로 created_at, updated_at 같은 이름을 씁니다.
💡 2️⃣ TIMESTAMP (PostgreSQL) / DATETIME (MySQL)
TIMESTAMP = 날짜와 시간 정보를 저장하는 데이터 타입
- 시각과 날짜를 함께 저장합니다.
- 예: '2025-10-09 14:32:00'
- PostgreSQL 기준으로 1970년 1월 1일부터의 시간(UTC)까지 관리할 수 있음
- TIMESTAMP 대신 DATETIME을 쓰는 DB도 있음 (MySQL 등)
💡 3️⃣ DEFAULT NOW()
DEFAULT NOW() = 값을 지정하지 않으면 현재 시각을 자동으로 넣어라
- 레코드 생성 시 값이 생략되면 DB가 자동으로 현재 시간을 넣어줌
- 예:
INSERT INTO users (name) VALUES ('Alice');
- 만약 created_at 컬럼에 값 지정 안하면 → 자동으로 2025-10-09 14:32:00 같은 현재 시각이 들어감
💡 4️⃣ 예시 전체
CREATE TABLE users (
id SERIAL PRIMARY KEY,
name VARCHAR(50) NOT NULL,
created_at TIMESTAMP DEFAULT NOW()
);
| 칼럼 | 의미 |
| id | 자동 증가 PK |
| name | 사용자 이름, NOT NULL |
| created_at | 레코드 생성 시각, 기본값 = 현재 시각 |
삽입 예시
INSERT INTO users (name) VALUES ('Alice');
- 결과 테이블:
| id | name | created_at |
| 1 | Alice | 2025-10-09 14:32:00 |
✔ 수동으로 값을 넣어도 됨:
💡 5️⃣ 요약
| 용어 | 의미 | 예시 |
| created_at | 컬럼 이름, 생성 시각 저장 | '2025-10-09 14:32:00' |
| TIMESTAMP | 날짜+시간 저장 타입 | '2025-10-09 14:32:00' |
| DEFAULT NOW() | 값 없으면 자동으로 현재 시간 삽입 | INSERT 시 생략하면 현재 시각 자동 |
Q. DEFAULT랑 NOW() 는 항상 같이 쓰는거야? TIMESTAMP 만 있고, DEFAULT NOW() 안 쓰면 어떻게 나와?
**답은 “아니요, 항상 세트로 다니는 건 아니다”**입니다.
1️⃣ DEFAULT와 NOW()의 관계
- DEFAULT
- 컬럼에 값이 없을 때 무슨 값을 기본으로 넣을지 지정하는 키워드
- 예: DEFAULT 0, DEFAULT 'unknown'
- 값만 지정해주면 어떤 것이든 가능
- NOW()
- 현재 시각을 반환하는 함수(Function)
- TIMESTAMP 타입과 주로 함께 쓰지만, 다른 곳에서도 함수로 사용 가능
🔹 함께 쓰는 경우
created_at TIMESTAMP DEFAULT NOW()
- 의미: 값 생략 시 현재 시각 넣어라
- TIMESTAMP 컬럼에서 자주 쓰임
🔹 따로 쓰는 경우
price INT DEFAULT 0
- 숫자 컬럼에 기본값 0 넣기
- 이때 NOW()와는 전혀 상관 없음
created_at TIMESTAMP
- TIMESTAMP만 있고 DEFAULT 안 붙이면 → 값 없으면 NULL
- 이때 NOW()도 붙이지 않음 → 자동 시간 입력 없음
✅ 요약
| 키워드 | 의미 | 항상 같이 쓰나? |
| DEFAULT | 값이 없으면 기본값 넣기 | X (값이면 어떤 것이든 가능) |
| NOW() | 현재 시각 반환 | X (DEFAULT나 INSERT에만 활용) |
| DEFAULT NOW() | 생략 시 현재 시각 자동 입력 | O (TIMESTAMP 컬럼에서 자주 사용) |
즉, DEFAULT와 NOW()는 서로 독립적이며, TIMESTAMP 컬럼에서 현재 시간을 자동 입력하고 싶을 때만 같이 씁니다.
이제 “created_at TIMESTAMP만 있을 때” 동작을 정확히 정리해드릴게요.
💡 1️⃣ 컬럼 정의
CREATE TABLE users (
id SERIAL PRIMARY KEY,
name VARCHAR(50),
created_at TIMESTAMP
);
- created_at 컬럼 타입은 TIMESTAMP
- DEFAULT나 NOT NULL 제약 없음 → 값 생략 가능
💡 2️⃣ 값 생략 시
INSERT INTO users (name) VALUES ('Alice');
- created_at 값을 넣지 않았으므로 → NULL이 들어갑니다.
결과 테이블:
| id | name | created_at |
| 1 | Alice | NULL |
💡 3️⃣ 값 지정 시
INSERT INTO users (name, created_at) VALUES ('Bob', '2025-01-01 10:00:00');
- 지정한 값 그대로 들어갑니다.
결과:
| id | name | created_at |
| 2 | Bob | 2025-01-01 10:00:00 |
💡 4️⃣ 요약
| 정의 | 값 생략 시 | 특징 |
| TIMESTAMP | NULL | 값 없으면 NULL, 자동 입력 없음 |
| TIMESTAMP DEFAULT NOW() | 현재 시각 | 값 생략 시 자동으로 현재 시간 입력 |
💬 핵심: TIMESTAMP만 있으면 “자동 시간 입력”이 되지 않고, 값 생략 시 NULL이 들어감
→ 자동으로 생성 시각을 기록하고 싶다면 DEFAULT NOW()를 써야 합니다.
Q. NOW() 는 현재 시각을 반환하는 '함수'라며. 이 함수는 어디에 정의되어있어서, 우리가 호출해서 쓸 수 있는 거야? MySQL 이나 PostgreSQL 에?
맞습니다, **NOW()는 DBMS가 제공하는 “내장 함수(built-in function)”**입니다.
1️⃣ 어디에 정의되어 있나?
- NOW() 함수는 MySQL, PostgreSQL 등 DBMS 내부에 정의되어 있음
- 즉,
우리가 직접 구현한 함수가 아니라 DB가 기본으로 제공하는 것
2️⃣ DB에서 어떻게 동작하나?
- NOW()를 호출하면 DB가 현재 서버 시각을 반환합니다.
- 예를 들어:
PostgreSQL
SELECT NOW();
결과:
2025-10-09 15:10:32.123456+00
MySQL
SELECT NOW();
결과:
2025-10-09 15:10:32
💬 DB 종류에 따라 출력 형식이나 정밀도(소수점 이하 초)가 조금 다를 수 있음
3️⃣ 어디서 사용할 수 있나?
- INSERT 시 기본값
INSERT INTO users (name, created_at) VALUES ('Alice', NOW());
- 컬럼 DEFAULT 값
created_at TIMESTAMP DEFAULT NOW()
- SELECT, UPDATE 등 쿼리 내에서 계산
UPDATE users SET last_login = NOW() WHERE id = 1;
4️⃣ 특징
- DB 서버 시각 기준 → 클라이언트 시각과 다를 수 있음
- 함수이므로 괄호() 사용 → NOW()
- PostgreSQL에서는 CURRENT_TIMESTAMP와 동의어
- MySQL도 동일하게 지원
✅ 요약
| 항목 | 의미 |
| NOW() | DB가 제공하는 내장 함수, 현재 시각 반환 |
| 정의 위치 | MySQL, PostgreSQL 등 DBMS 내부 |
| 사용 가능 위치 | SELECT ~ FROM , INSERT INTO ~ VALUES, UPDATE ~ SET, DEFAULT 등 쿼리 내 |
Q. DBMS
DBMS는 데이터베이스를 다루는 핵심 시스템이에요.
💡 1️⃣ DBMS란?
DBMS(Database Management System) = 데이터베이스 관리 시스템
즉, 데이터를 안전하고 효율적으로 조회, 수정, 저장, 관리할 수 있도록 도와주는 소프트웨어입니다.
2️⃣ DBMS가 하는 일
- 데이터 저장
- 데이터를 구조화하여 디스크에 안전하게 저장
- 예: 테이블, 컬럼, 레코드 형태
- 데이터 조회/수정
- SQL 같은 질의 언어로 데이터를 읽고 쓰는 기능 제공
- 무결성 유지
- PK, FK / NOT NULL, UNIQUE 등의 제약 조건을 적용
- 동시성 제어
- 여러 사용자가 동시에 접근해도 데이터 일관성 유지
- 보안 관리
- 권한과 접근 제어
3️⃣ DBMS 종류
| DBMS | 특징 |
| MySQL | 오픈소스 / 웹 서비스에서 많이 사용 |
| PostgreSQL | 오픈소스, 기능 강력, 복잡한 쿼리 가능 |
| SQLite | 가벼움, 파일 기반 / 모바일/임베디드 |
| Oracle DB | 상용, 대규모 기업용 |
| SQL Server | Microsoft 상용, Windows 환경 최적화 |
4️⃣ DBMS vs 데이터베이스
- 데이터베이스(Database)
- 실제 데이터를 저장하는 공간
- 예: users 테이블, articles 테이블
- DBMS
- 데이터를 관리하는 소프트웨어
- 예: MySQL, PostgreSQL, Oracle
즉, DBMS가 있어야 데이터베이스를 만들고 관리할 수 있음
✅ 요약
| 용어 | 의미 | 예시 |
| DBMS | 데이터 관리 시스템 | MySQL, PostgreSQL |
| Database | 데이터를 저장하는 공간 | my_blog_db |
| Table | 데이터를 구조화한 단위 | users, posts |
| Row | 한 레코드 | id=1, name='Alice' |
| Column | 속성 | name, email |
Q. 레코드
데이터베이스에서 **레코드(Record)**는 핵심 단위 중 하나입니다.
💡 1️⃣ 레코드(Record)란?
레코드(Record) = 테이블 한 줄(Row)에 들어있는 데이터 단위
즉, 하나의 개체(Entity) 정보를 담고 있는 데이터 집합입니다.
- 테이블 = 사람들을 저장하는 구조라면
- 레코드 = 한 사람 정보 한 줄
🔍 예시 테이블
users 테이블:
| id | name | |
| 1 | Alice | alice@example.com |
| 2 | Bob | bob@example.com |
- 첫 번째 레코드: id=1, name='Alice', email='alice@example.com'
- 두 번째 레코드: id=2, name='Bob', email='bob@example.com'
🔹 한 줄 전체가 레코드입니다.
🔹 각각의 컬럼(Column) 값이 모여 하나의 레코드가 됨
💡 2️⃣ 레코드 vs 컬럼
| 용어 | 의미 | 예시 |
| 컬럼(Column) | 테이블의 속성 | id, name, email |
| 레코드(Record) | 한 행(Row), 속성값들의 집합 | 1, Alice, alice@example.com |
- 컬럼은 가로 축 (속성)
- 레코드는 세로 축 (데이터 한 단위)
💡 3️⃣ ERD 관점
- 엔티티(Entity) = 테이블 설계
- 속성(Attribute) = 컬럼
- 레코드(Record) = 엔티티 인스턴스(실제 데이터)
예: User 엔티티 → 레코드 1개 = Alice라는 실제 사용자 데이터
✅ 요약
| 용어 | DB 관점 의미 | 코드/비유 |
| 테이블 | 데이터 구조 (users / post ..) |
클래스 |
| 컬럼 | 속성 (id, name, email ..) |
클래스 필드 |
| 레코드 | 한 데이터 단위 (id=1 / name='Alice' / email="abc@naver.com") |
클래스 인스턴스/객체 |
| 행(Row) | 레코드와 동일 | 한 줄 데이터 |
Q. 클래스 필드 / 클래스 인스턴스 / 클래스 객체
이제 데이터베이스와 객체 지향 개념을 연결해서 이해해보면 좋습니다.
클래스, 필드, 인스턴스, 객체 개념을 하나씩 차근차근 설명할게요.
💡 1️⃣ 클래스(Class)란?
클래스 = 객체를 만들기 위한 설계도(템플릿)
- 속성과 동작을 정의해 놓은 구조
실제 데이터를 담고 있지 않고, “이런 구조를 가진 객체를 만들겠다”라는 설계
예시 (TypeScript)
class User {
name: string;
email: string;
constructor(name: string, email: string) {
this.name = name;
this.email = email;
}
greet() {
console.log(`Hello, ${this.name}`);
}
}
- User 클래스 = 설계도
- 속성(name, email)과 동작(greet)을 정의
💡 2️⃣ 클래스 필드(Class Field)란?
클래스 필드 = 클래스 안에서 정의된 속성(attribute, property)
- 객체가 가지는 데이터 항목
- 위 예제에서 name과 email이 클래스 필드
💡 3️⃣ 클래스 인스턴스(Class Instance) / 객체(Object)
인스턴스 = 클래스로부터 실제로 생성된 구체적 데이터
객체 = 인스턴스와 동일하게 생각할 수 있음
const alice = new User('Alice', 'alice@example.com');
const bob = new User('Bob', 'bob@example.com');
- alice = User 클래스의 인스턴스(객체)
- name = 'Alice', email = 'alice@example.com'
- bob = 또 다른 인스턴스(객체)
즉, 클래스는 설계도, 인스턴스/객체는 실제 데이터
💡 4️⃣ DB 테이블과 클래스 비교
| DB 용어 | 객체 지향(OOP) 용어 | 설명 |
| 테이블 | 클래스 | 구조 설계 |
| 컬럼 | 클래스 필드 | 속성 정의 |
| 레코드 | 인스턴스/객체 | 실제 데이터 한 단위 |
| 행(Row) | 인스턴스/객체 | 동일 |
예시 매칭
- users 테이블 (DB)
id name email 1 Alice alice@example.com 2 Bob bob@example.com - OOP에서 클래스(User)로 만든 객체(alice, bob)
- alice.name = 'Alice', alice.email = 'alice@example.com'
- bob.name = 'Bob', bob.email = 'bob@example.com'
💡 5️⃣ 그림으로 비유
[User 클래스] ← 설계도
name
email
greet()
↓ new User(...)
[alice 객체/인스턴스]
name = 'Alice'
email = 'alice@example.com'
[bob 객체/인스턴스]
name = 'Bob'
email = 'bob@example.com'
클래스 = 설계도
객체/인스턴스 = 설계도로 만든 실제 제품
TypeScript 클래스 구조를 완전히 이해하면 OOP와 DB 연관 개념도 훨씬 쉽게 이해돼요.
1️⃣ 클래스 전체 구조 설명
class User {
name: string;
email: string;
constructor(name: string, email: string) {
this.name = name;
this.email = email;
}
greet() {
console.log(`Hello, ${this.name}`);
}
}
- class User { ... } → User라는 클래스 정의
- name: string; email: string; → 클래스 필드(속성), User 객체가 갖는 데이터
- constructor(name: string, email: string) { ... } → 객체 생성 시 실행되는 초기화 함수
- greet() → User 객체가 가진 동작(메서드), 콘솔에 인사 출력
즉, User 클래스는 설계도이고, new User('Alice', 'alice@example.com')로 **인스턴스(객체)**를 만들 수 있어요.
2️⃣ constructor와 메서드(greet)의 차이
- constructor()
- 클래스를 기반으로 객체를 만들 때 자동으로 호출되는 함수
- 객체의 초기값을 설정하는 용도
- 호출 방식: new User('Alice', 'alice@example.com')
- greet()
- 객체가 가진 일반 동작(메서드)
- 호출 방식: user.greet()
💡 핵심:
- constructor는 “생성할 때 자동 실행되는 초기화 함수”
- greet()는 객체 만든 후 호출하는 동작
3️⃣ constructor 매개변수 타입 지정 이유
constructor(name: string, email: string) { ... }
- 클래스 필드 name: string;과 동일 타입을 지정하는 이유:
- 매개변수 타입 지정 → TS 컴파일러가 타입 체크 가능
- 객체 생성 시 ㅠ(new User(...))이 올바른 타입인지 확인
- 즉, 필드 타입과 매개변수 타입이 같아야 필드에 안전하게 할당 가능
4️⃣ this.name = name; this.email = email; 설명
- this → 현재 객체 자신을 가리킴
- this.name = name 의미:
- this.name → User 객체의 필드 name
- name → constructor 매개변수 name
- 즉, 객체 필드에 매개변수 값을 할당
const alice = new User('Alice', 'alice@example.com');
// User 객체(인스턴스)
{
name: 'Alice'
email: 'alice@example.com'
}
- 실행 과정:
- constructor 매개변수 name='Alice', email='alice@example.com'
- this.name = 'Alice', this.email = 'alice@example.com'
5️⃣ ${this.name}와 문자열 보간
console.log(`Hello, ${this.name}`);
- 백틱(`) + ${} → 템플릿 문자열(Template String)
- ${} 안에 변수/표현식을 넣으면 문자열 안에 값을 넣을 수 있음
왜 this.name을 넣는가?
- name → constructor 매개변수
- this.name → 객체의 필드(name)
- greet()는 객체가 만들어진 후 호출되므로,
매개변수 name은 존재하지 않음 → constructor 밖에서는 this.name 사용
class User {
name: string;
email: string;
constructor(name: string, email: string) {
this.name = name;
this.email = email;
}
greet() {
console.log(`Hello, ${this.name}`);
}
}
// 객체 생성할 때 -> 초기화함수 constructor() 실행
const alice = new User('Alice', 'alice@example.com');
// 객체 필드에 매개변수 값 할당
{
name: 'Alice',
email: 'alice@example.com'
}
alice.greet(); // Hello, Alice
- greet()는 constructor 범위 밖 → 매개변수 name 접근 불가
- 반드시 **this.name(객체 필드)**을 사용해야 함
✅ 정리
| 용어 | 의미 |
| class User { ... } | 설계도, 클래스 정의 |
| name: string | 클래스 필드, 객체 속성 |
| constructor(name: string, email: string) | 객체 생성 시 실행, 초기값 설정 |
| this | 현재 객체 자신 |
| this.name = name | 객체 필드(name)에 매개변수 값(name) 할당 |
| greet() | 객체가 가진 동작, 메서드 |
| ${this.name} | 템플릿 문자열로 객체 필드 값을 -> 문자열 안에 삽입 |
Q. console.log(`Hello, ${this.name}`)
문자열 안에 동적으로 변하는 값을 넣을 때 **백틱(`) + ${}**를 사용합니다.
이걸 템플릿 문자열(Template String) 또는 템플릿 리터럴이라고 해요.
1️⃣ 사용 예시
const name = "Alice";
console.log(`Hello, ${name}!`); // Hello, Alice!
- ${name} → 변수 name의 값을 문자열 안에 넣음
- 기존 "Hello, " + name + "!"처럼 + 연산자 없이 간단하게 작성 가능
2️⃣ 키보드에서 백틱(`) 입력 방법
- Windows:
- 보통 왼쪽 상단 숫자 1 왼쪽 키
- Shift 없이 한 번 누르면 ` 입력
- Mac:
- 왼쪽 상단 숫자 1 왼쪽 키, Shift 없이
- 주의:
- 작은 따옴표 ' '나 큰 따옴표 " "와 다릅니다.
- 백틱은 문자열 시작과 끝을 `로 감싸야 ${} 사용 가능
3️⃣ 기존 문자열과 비교
const name = "Alice";
const day = "Friday";
// 기존 방식
console.log("Hello, " + name + "!");
// 템플릿 문자열
console.log(`Hello, ${name}!`);
console.log(`Hello, ${name}!
Today is ${day}.`);
- 템플릿 문자열이 훨씬 직관적이고, 줄바꿈, 변수 삽입도 쉽게 가능
결과:
Hello, Alice!
Today is Friday.
🚦 5. API ↔ DB 매핑 검증
이제 API 요청/응답이 -> DB 구조에 맞게 동작하는지를 확인합니다.
예:
- GET /users/{id} → SELECT * FROM users WHERE id = $1
- POST /posts → INSERT INTO posts (...) VALUES (...)
- 응답 JSON 구조가 DB 스키마와 일관성 있는지 확인
Q. DBMS 쿼리
1️⃣ DBMS 쿼리 종류
SQL(Structured Query Language)은 크게 5가지 유형으로 나뉩니다.
| 분류 | 설명 | 예시 |
| DDL (Data Definition Language) | 데이터베이스 구조 정의 | CREATE TABLE ALTER TABLE DROP TABLE |
| DML (Data Manipulation Language) | 데이터 조작 (삽입/수정/삭제) | INSERT UPDATE DELETE |
| DQL (Data Query Language) | 데이터 조회 | SELECT |
| DCL (Data Control Language) | 권한 관리 | GRANT REVOKE |
| TCL (Transaction Control Language) | 트랜잭션 관리 | COMMIT ROLLBACK SAVEPOINT |
💡 핵심:
- DDL → 테이블 구조 변경
- DML → 데이터 내용 변경
- DQL → 데이터 조회
2️⃣ SELECT 쿼리
SELECT * FROM users WHERE id = $1;
🔹 구성 요소
| 구문 | 의미 |
| SELECT * | 모든 컬럼을 조회 (* = 전체 컬럼) |
| FROM users | 조회할 테이블 이름 |
| WHERE id = $1 | 조건 지정 / id가 $1인 행만 선택 |
🔹 $1 의미
- $1 → 파라미터 바인딩(Placeholder)
- 쿼리 실행 시 외부에서 값을 넣는 자리 표시자
- 예: Node.js PostgreSQL 라이브러리(pg)에서
const id = 5;
const result = await pool.query('SELECT * FROM users WHERE id = $1', [id]);
- $1 → 배열 [id]의 첫 번째 값(5)로 치환
- SQL 인젝션 방지에도 중요
🔹 실행 과정 예시
| id |
| ---- |
| 1 |
| 2 |
- id = 2를 바인딩하면 결과: (WHERE id = $2) (id가 $2인 행만 선택)
| id | name | |
| 2 | Bob | bob@example.com |
3️⃣ 요약
- DBMS 쿼리 종류
- DDL: 테이블 구조 변경
- DML: 데이터 삽입/수정/삭제
- DQL: 데이터 조회
- DCL: 권한 관리
- TCL: 트랜잭션 관리
- SELECT * FROM users WHERE id = $1
- users 테이블에서 특정 조건(id=$1)에 맞는 행 조회
- $1은 파라미터 자리 표시자
- Node.js 등에서 실제 값으로 치환 가능
1️⃣ SQL 인젝션(SQL Injection)
SQL 인젝션 =
악의적인 사용자가 입력값을 조작해서, DB 쿼리를 변조하고
의도치 않은 데이터를 조회/삭제/변경하는 공격
🔍 예시
const userInput = "' OR 1=1; --";
const query = `SELECT * FROM users WHERE name = '${userInput}'`;
- 원래 의도: 특정 이름 조회 (users 테이블의 모든 컬럼 중, name이 ${userInput}인 행 조회)
- 공격: ' OR 1=1; -- → 모든 데이터 조회 가능
- 결과: DB에 있는 모든 사용자 정보를 가져올 수 있음
✅ 방어 방법
- 파라미터 바인딩 사용 ($1, ?) → 값만 전달, 쿼리 구조는 안전
const result = await pool.query(
'SELECT * FROM users WHERE name = $1',
[userInput]
);
- 이렇게 하면 입력값이 쿼리에 직접 삽입되지 않아 안전
2️⃣ CRUD
CRUD = 데이터베이스에서 기본적인 데이터 조작 작업 4가지
| Create | 생성 | 새로운 데이터 삽입 | INSERT INTO users (name) VALUES ('Alice'); | |
| Read | 조회 | 데이터 조회 | SELECT * FROM users WHERE id=1; | |
| Update | 수정 | 데이터 수정 | UPDATE users SET name='Bob' WHERE id=1; | |
| Delete | 삭제 | 데이터 삭제 | DELETE FROM users WHERE id=1; |
- CRUD는 SQL 명령어와 1:1 매칭되는 개념
- 즉, SQL(언어)로 -> CRUD 작업을 수행(행위)한다고 이해하면 됨
3️⃣ SQL과 CRUD의 관계
- SQL(Structured Query Language) = 데이터베이스와 소통하기 위한 언어
- CRUD = SQL로 수행하는 -> 기본 데이터 조작 작업 4가지 (생성,조회,수정,삭제)
- 예: SQL은 언어, CRUD는 행위
SQL → 언어
CRUD → SQL로 할 수 있는 행동
🔹 요약
| 용어 | 의미 |
| SQL Injection | 사용자 입력값으로 쿼리를 조작하여 공격하는 기법 |
| CRUD | 데이터 생성, 조회, 수정, 삭제의 4가지 기본 동작 |
| SQL | 데이터베이스와 소통하기 위한 언어, CRUD 작업을 SQL로 수행 |
Q. 쿼리 (Query)
한줄 정리
- 쿼리(query) = 데이터베이스에 “요청(질문)”을 하는 한 건의 명령문(문장)
- SQL = 그 쿼리를 작성하는 언어(도구) 중 하나 — Structured Query Language.
즉, 쿼리 = (SQL로 쓸 수 있는) 하나의 요청문, SQL = 그 요청문들을 쓰는 언어라고 보면 됩니다.
좀 더 풀어서
1) 쿼리(query)는 무엇인가?
- 쿼리는 정보를 얻거나(조회), 데이터를 추가/수정/삭제하는(조작) 모든 “데이터 관련 요청”을 의미합니다.
- 보통 하나의 문장(statement) 로 표현됩니다. 예:
- SELECT * FROM users WHERE id = 1; ← 조회 쿼리
- INSERT INTO users (name) VALUES ('Alice'); ← 생성(조작) 쿼리
- UPDATE users SET name = 'Bob' WHERE id = 1; ← 수정 쿼리
참고: 많은 사람은 “쿼리” 하면 SELECT(조회)를 먼저 떠올리지만, 엄격히 말하면 INSERT/UPDATE/DELETE 같은 것도 모두 쿼리입니다.
2) SQL과의 관계 :: SQL -> Query
- SQL = 데이터베이스와 대화하기 위해 만든 표준 언어(문법)
- SQL로 작성된 각 문장(Statement) 이 바로 쿼리입니다.
- 즉, “SQL 쿼리”라고 부르면 그건 SQL 문장 하나(쿼리)를 말하는 것.
- 비유:
- SQL = 영어,
- 쿼리 = 영어로 쓴 편지 한 통.
3) 쿼리의 종류(실무 관점)
- 조회 쿼리 (SELECT) — 데이터 읽기 (주로 DQL)
- 삽입 쿼리 (INSERT) — 새 레코드 추가 (DML)
- 수정 쿼리 (UPDATE) — 기존 레코드 수정 (DML)
- 삭제 쿼리 (DELETE) — 레코드 삭제 (DML)
- 구조 변경 쿼리 (CREATE/ALTER/DROP) — 테이블/스키마 변경 (DDL)
- 권한/트랜잭션 관련 쿼리 (GRANT, COMMIT) 등
모두 쿼리라고 부를 수 있습니다.
4) 쿼리 vs 명령(command) vs 질의(question)
- 실무에서는 혼용해서 쓰지만 미세 차이:
- 쿼리(query) / 질의(question): 주로 “데이터를 조회하는 요청” 의미로 쓰이기도 함.
- 명령(command) / statement: 더 넓은 의미로 “DB에 실행을 지시하는 모든 문장” (조회·삽입·수정·삭제 포함).
- 요약: 모두 같은 맥락에서 섞어 써도 무방하나, 엄밀히는 “쿼리 = DB에 대한 한 건의 요청문”.
5) 쿼리 실행의 실제 (짧은 흐름)
- 애플리케이션이 SQL 쿼리를 -> DB 드라이버에 보냄.
- 드라이버/DB가 쿼리 파싱 → 실행 계획 생성 → 실행 → 결과 반환.
- (중요) 파라미터 바인딩을 사용해, 쿼리와 데이터를 분리하면 SQL 인젝션을 방어할 수 있음.
예:
-- 안전한 파라미터화 예 (Postgres)
SELECT * FROM users WHERE id = $1;
-- $1 자리에 실제 값이 바인딩되어 전달됨
6) 쿼리는 SQL만 있는 게 아니다
- GraphQL 쿼리, Elasticsearch 쿼리 DSL, MongoDB 쿼리 객체 등
- 즉, 쿼리라는 개념은 “데이터에 질문하는 표현” 자체이고, SQL은 관계형 DB에서의 표준 언어일 뿐입니다.
핵심 요약 (짧고 굵게)
- 쿼리 = 데이터베이스에 하는 하나의 요청(문장)
- SQL = 쿼리를 쓰는 언어(도구)
- SELECT/INSERT/UPDATE/DELETE 등 모두 쿼리로 불릴 수 있다.
- 쿼리 작성 시 **파라미터화(Prepared Statement)**로 보안(예: SQL 인젝션)과 성능을 챙기세요.
🧰 6. ORM(Model) 설계
ORM (ex: Prisma, TypeORM, Sequelize, SQLAlchemy) 을 사용한다면:
- 모델 이름은 엔티티명과 일치
- 관계는 명시적으로 정의 (hasMany, belongsTo 등)
- 마이그레이션 스크립트 자동 생성
예 (TypeORM):
@Entity()
export class Post {
@PrimaryGeneratedColumn()
id: number;
@Column()
title: string;
@ManyToOne(() => User, user => user.posts)
author: User;
}
📋 7. 검증 & 피드백
- API 스펙 변경에 따른 스키마 영향 점검
- 실제 테스트 데이터로 쿼리 성능 테스트
- 비즈니스 로직에서 필요한 인덱스 추가
Q. 인덱스 란?
데이터베이스에서 “인덱스(Index)”는 성능과 직결되기 때문에 꼭 이해해야 합니다.
💡 1️⃣ 인덱스(Index)란?
인덱스(Index) = 책의 목차처럼 DB 검색 속도를 빠르게 해주는 구조
즉, DB에서 특정 데이터를 빠르게 찾기 위해 별도로 만든 자료 구조입니다.
- 인덱스 없으면 DB는 테이블의 모든 데이터를 하나씩 뒤져야 해서 느려짐
- 인덱스 있으면 바로 위치를 찾아서 조회 속도가 빨라짐
🔍 비유로 이해하기
- 책 = DB 테이블
- 목차 = 인덱스
- “‘Chapter 5’ 페이지가 어디인지 찾아라”
- 목차 있음 → 바로 페이지 이동 ✅
- 목차 없음 → 1페이지부터 하나씩 확인 ❌ (느림)
💡 2️⃣ 실제 예시
테이블
CREATE TABLE users (
id SERIAL PRIMARY KEY,
name VARCHAR(50),
email VARCHAR(100)
);
- id 컬럼은 기본키(primary key) 이므로 자동으로 인덱스가 생성됨 → 검색 빠름
- 하지만 email 컬럼으로 자주 검색한다면 → 인덱스를 추가하는 게 좋음
CREATE INDEX idx_users_email ON users(email);
이제:
SELECT * FROM users WHERE email = 'alice@example.com';
- 인덱스 덕분에 전체 테이블 스캔(full table scan) 없이 바로 찾을 수 있음
💡 3️⃣ 인덱스 종류
| 종류 | 설명 | 예시 |
| 기본키 인덱스(PK) | 기본키 컬럼 자동 생성 | id |
| 단일 컬럼 인덱스 | 특정 컬럼 하나 | |
| 복합 인덱스(Composite Index) | 여러 컬럼 조합 | (first_name, last_name) |
| 유니크 인덱스(Unique Index) | 중복 허용 안 함 |
💡 4️⃣ 주의할 점
- 인덱스 많다고 무조건 좋은 건 아님
- 쓰기/수정/삭제 성능이 느려짐 (인덱스도 같이 갱신해야 하므로)
- 자주 조회하는 컬럼 / WHERE나 JOIN에 자주 쓰이는 컬럼 중심으로 추가
🧠 요약
| 용어 | 의미 | 예시 |
| 인덱스(Index) | 데이터를 빠르게 검색하도록 돕는 자료 구조 | 책의 목차 |
| 자동 인덱스 | PK, UNIQUE 컬럼 | id, email(유니크) |
| 수동 인덱스 | 자주 검색하는 컬럼 추가 | CREATE INDEX idx_users_email ON users(email); |
Q. 자동 인덱스
“자동 인덱스(Auto Index)”는 DB 설계에서 자주 나오지만, 개념을 명확히 이해하는 게 중요합니다.
💡 1️⃣ 자동 인덱스란?
자동 인덱스(Automatic Index) = DB가 자동으로 생성해주는 인덱스
즉, 개발자가 따로 CREATE INDEX를 하지 않아도 DB가 알아서 만들어주는 인덱스입니다.
자동 인덱스는 보통 검색과 무결성 유지를 위해 필요한 곳에 생성됩니다.
🔍 2️⃣ 자동 인덱스가 생성되는 경우
| 상황 | 설명 | 예시 |
| Primary Key | 기본키는 중복 허용 불가 + 검색 빠르게 해야 함 | id SERIAL PRIMARY KEY |
| Unique Key / Unique Constraint | 유일성을 보장하기 위해 자동 생성 | email VARCHAR(100) UNIQUE |
| Foreign Key (DB에 따라 다름) | 참조 무결성을 위해 내부적으로 생성 | author_id INT REFERENCES users(id) |
💬 즉, 자동 인덱스는 데이터 무결성과 검색 성능을 위해 DB가 알아서 추가해주는 인덱스입니다.
💡 3️⃣ 예시 — PostgreSQL
CREATE TABLE users (
id SERIAL PRIMARY KEY, -- 자동 인덱스 생성
email VARCHAR(100) UNIQUE -- 자동 인덱스 생성
);
- id → PK 자동 인덱스
- email → UNIQUE 자동 인덱스
- 별도로 CREATE INDEX 안 해도 검색할 때 사용 가능
💡 4️⃣ 특징
- 자동 생성 → 개발자가 신경 쓰지 않아도 됨
- 주로 PK와 UNIQUE 컬럼 중심
- 조회 속도 향상 → WHERE 절에서 컬럼을 검색할 때 사용
- 쓰기 성능 영향 → 데이터 삽입/수정 시 자동 인덱스도 갱신됨
💡 5️⃣ 수동 인덱스와 비교
| 구분 | 자동 인덱스 | 수동 인덱스 |
| 생성 주체 | DB | 개발자 |
| 생성 시점 | PK/UNIQUE 지정 시 자동 | 필요 시 CREATE INDEX |
| 용도 | 무결성 + 검색 | 조회 성능 최적화 |
| 예시 | id PRIMARY KEY, email UNIQUE | idx_users_created_at |
💡 요약하면:
자동 인덱스 = DB가 필수적으로 필요하다고 판단되는 컬럼(PK, UNIQUE 등)에 대해 자동으로 생성하는 인덱스
수동 인덱스 = 개발자가 조회 성능 향상을 위해 직접 추가하는 인덱스
✅ 요약
| 단계 | 내용 |
| 1 | API 명세로 리소스 추출 |
| 2 | 엔티티/관계 도출 & ERD 작성 |
| 3 | 정규화 및 비정규화 검토 |
| 4 | SQL 스키마 설계 |
| 5 | API ↔ DB 매핑 검증 |
| 6 | ORM 모델화 |
| 7 | 성능/변경 검증 |
'프로그래밍' 카테고리의 다른 글
| 서버 오픈 시간 늦는 이유 (0) | 2025.10.23 |
|---|---|
| 구글 스프레드시트 스크립트 :: Google Apps Sciprt(GAS) (0) | 2025.10.23 |
| 인증, 권한 관리 (0) | 2025.10.10 |
| 인증, 권한 관리 (0) | 2025.10.10 |
| 백엔드 API 명세 설계 예시 (0) | 2025.10.09 |
| 백엔드 API 명세 설계 예시 (0) | 2025.10.09 |
| fetch API 의 응답 분석 :: response, data 의 정체는? (0) | 2025.10.08 |
| 엔드포인트 란? API 호출과의 연관성 (0) | 2025.10.08 |