Part 1. MySQL 기본
Q1. DB와 DBMS의 차이는 무엇인가요?
DB(Database)는 저장된 데이터의 집합 자체이며, DBMS(Database Management System)는 데이터를 저장, 관리, 조회할 수 있도록 도와주는 소프트웨어입니다.
상세 설명
- 예를 들어 서비스의 회원 정보나 주문 내역이 파일이나 디스크에 저장되어 있는 상태 데이터 자체가 Database입니다. 이러한 데이터를 효율적으로 읽고, 쓰고, 안전하게 보호하기 위해 사용하는 프로그램(예: MySQL, PostgreSQL, Oracle)이 바로 DBMS입니다.
실무 포인트
- "Database = MySQL"이 아닙니다. MySQL은 DBMS입니다.
꼬리 질문
- RDBMS 외에 다른 종류의 DBMS는 어떤 것이 있나요?
- NoSQL DBMS가 대표적입니다. 데이터 모델에 따라 Key-Value(Redis), Document(MongoDB), Column Family(Cassandra), Graph(Neo4j) 등으로 나뉩니다. 정해진 스키마 없이 유연한 구조와 높은 확장성을 제공하는 것이 특징입니다.
- File System으로 데이터를 관리하지 않고 DBMS를 사용하는 이유는 무엇인가요?
- 파일 시스템은 데이터 중복, 동시성 제어, 검색 성능, 무결성 관리에 한계가 있습니다. 반면, DBMS는 트랜잭션, 인덱스, 동시성 제어, 백업/복구 기능을 제공하여 데이터를 안정적이고 효율적으로 관리할 수 있기 때문입니다.
Q2. RDBMS란 무엇인가요?
관계형 데이터 모델을 기반으로, 테이블 간의 관계를 활용해 데이터를 구조화하고 관리하는 데이터베이스 관리 시스템입니다.
상세 설명
- Relational Database Management System의 약자로, 모든 데이터를 2차원 테이블(Table) 형태로 저장합니다.
- Primary Key(기본 키)와 Foreign Key(외래 키)를 사용해 테이블 간의 연관 관계를 정의합니다.
- 데이터의 중복을 최소화(정규화)하고, SQL(Structured Query Language)이라는 표준 언어를 통해 데이터를 제어합니다.
실무 포인트
- RDBMS를 설명할 때 "테이블 간의 관계"가 실제 서비스 데이터 모델링에서 어떻게 적용되는지 예시를 들어 설명하면 좋습니다. 예를 들어, `members` 테이블의 PK(`id`)를 `orders` 테이블이 FK(`member_id`)로 참조함으로써 회원과 주문 간의 1:N 관계를 형성합니다.
꼬리 질문
- Foreign Key는 무조건 설정하는 것이 좋을까요? 실무적 단점은 없나요?
- 데이터 무결성을 보장하는 강력한 장점이 있지만, CUD 연산 시 성능 저하가 발생할 수 있습니다. 또한 대용량 서비스에서는 마이그레이션이나 샤딩(Sharding)을 복잡하게 만드는 원인입니다. 따라서 실무에서는 데이터 중요도에 따라 FK를 걸거나, 애플리케이션 로직으로 무결성을 제어하기도 합니다.
- JOIN 연산이 많아지면 성능에 어떤 영향이 생기나요?
- 읽어야 할 데이터량과 비교 연산이 급증하여 조회 성능이 저하됩니다. 특히 인덱스가 적절히 설정되어 있지 않거나 대용량 테이블 간 JOIN이 일어나면 Full Scan으로 인해 심각한 병목이 발생하므로, 필요한 컬럼만 추출하고 인덱스를 철저히 설계해야 합니다.
Q3. MySQL이란 무엇인가요?
MySQL은 Oracle 사에서 관리하는 오픈소스 관계형 데이터베이스 관리 시스템(RDBMS)입니다. 데이터를 테이블 형태로 관리하고 SQL을 사용하여 조회 및 조작합니다.
상세 설명
- MySQL은 데이터를 행(Row)과 열(Column)로 구성된 테이블에 저장하는 관계형 데이터베이스 관리 시스템(RDBMS)입니다.
- 관계형 모델을 기반으로 하여 Primary Key와 Foregin Key 등을 이용해 데이터 간의 관계를 정의하고 관리합니다.
- ACID 속성을 준수하는 트랜잭션을 지원하며, InnoDB를 기본 스토리지 엔진으로 사용하여 높은 동시성과 데이터 무결성을 보장합니다.
- 웹 애플리케이션 및 Spring Boot 기반 백엔드 시스템에서 가장 널리 사용되는 데이터베이스 중 하나입니다.
실무 포인트
- 단순히 "관계형 데이터베이스입니다."라고 답변하기보다는, "InnoDB 스토리지 엔진을 기본으로 사용하여 MVCC와 Row Level Lock을 통해 동시성 처리를 지원하는 RDBMS입니다."라고 답변하면 훨씬 좋습니다.
꼬리 질문
- NoSQL과 차이점은 무엇인가요?
- RDBMS는 명확한 스키마, JOIN, 강력한 트랜잭션에 강점이 있어 금융/결제 서비스처럼 데이터 정합성이 중요할 때 쓰입니다. 반면 NoSQL은 유연한 스키마와 수평 확장성(Scale-Out)이 뛰어나 대규모 로그 수집이나 캐싱에 적합합니다.
- 왜 수많은 DB 중 MySQL을 선택해 사용하셨나요?
- 오픈소스 생태계가 풍부하고, 오랜 시간 검증되어 성능과 안정성이 뛰어납니다. 또한 Spring Boot와 생태계와 연동이 매우 매끄럽고, 문제 발생 시 빠르게 해결할 수 있을 만큼 커뮤니티와 참고 자료가 풍부합니다.
Q4. MySQL의 특징은 무엇인가요?
높은 오픈소스 생태계, InnoDB 기반의 강력한 트랜잭션 및 ACID 지원, 그리고 MVCC와 Row Lock을 통한 우수한 동시성 및 안정성이 대표적인 특징입니다.
상세 설명
- 무료 오픈소스로 제공되며 커뮤니티 생태계가 매우 풍부합니다.
- 플러그인 형태의 스토리지 엔진 구조를 채택하여 용도에 맞는 엔진을 선택할 수 있습니다.
- 기본 엔진인 InnoDB를 통해 ACID 트랜잭션, MVCC, Row Level Locking을 지원하여 높은 읽기/쓰기 성능을 제공합니다.
- Master-Slave 기반의 Replication(복제) 기능을 제공하여 읽기 트래픽 분산 및 고가용성 아키텍처 구성이 용이합니다.
실무 포인트
- MySQL의 가장 큰 장점은 스토리지 엔진 아키텍처의 유연성과 InnoDB 기반의 동시성 제어 능력입니다.
꼬리 질문
- MyISAM과 InnoDB의 차이는 무엇인가요?
- 트랜잭션 지원 여부가 가장 큰 차이입니다. InnoDB는 트랜잭션, MVCC, Row Level Lock, Foregin Key를 지원해 동시성과 정합성을 모두 확보하지만, MyISAM은 이를 지원하지 않고 Table Level Lock을 사용합니다.
- 왜 MySQL 5.5/5.7 이후부터 InnoDB가 기본 스토리지 엔진이 되었나요?
- 동적인 웹 서비스 특성상 데이터 정합성과 빠른 동시성 처리가 필수적이었기 때문입니다. InnoDB는 트랜잭션, Row Lock, Crash Recovery을 통해 높은 안정성과 고성능을 동시에 제공합니다.
Q4. MySQL Architecture를 설명해주세요.
MySQL 아키텍처는 크게 Connection 관리 및 SQL 처리를 담당하는 MySQL 엔진(Server Layer), 그리고 실제 디스크에 데이터를 저장하고 읽어오는 스토리지 엔진(Storage Engine Layer)으로 구분됩니다.
상세 설명
- MySQL Server Layer(엔진 레이어)
- Connection Handler: 클라이언트의 연결 및 인증을 관리합니다.
- SQL Parser: SQL 구문 오류를 검사하고 파스 트리(Parse Tree)로 변환합니다.
- Optimizer: 쿼리를 효율적으로 실행하기 위한 실행 계획(Execution Plan)을 수립합니다.
- Executor: Optimizer가 만든 실행 계획에 따라 스토리지 엔진을 호출하여 결과를 반환합니다.
- Storage Engine Layer
- 실제 디스크나 메모리에 데이터를 저장하고 읽어오는 역할을 담당하며, 대표적으로 InnoDB가 있습니다.
실무 포인트
- "클라이언트 요청 → Parser → Optimizer → Executor → Storage Engine → Disk"의 처리 흐름을 단계별로 명확하게 설명할 수 있어야 합니다. 특히 Optimizer가 실행 계획을 세운다는 점이 핵심입니다.
꼬리 질문
- Optimizer는 어떻게 최적의 실행 계획을 판단하나요?(통계 정보)
- 테이블 및 인덱스의 통계 정보를 바탕으로, 각 실행 방식에 대한 비용(Cost)을 계산합니다. 이 중 가장 적은 비용이 예상되는 방식을 선택하는 비용 기반 최적화(CBO, Cost-Based Optimizer) 방식으로 동작합니다.
- Server Layer와 Storage Engine Layer가 분리되어 얻는 구조적 이점은 무엇인가요?
- 역할과 책임이 명확히 분리됩니다. Server Layer는 파싱, 최적화, 캐싱 등 표준 공통 로직을 담당하고, Storage Engine Layer는 디스크 저장 및 조회를 담당합니다. 이를 통해 애플리케이션이 변경 없이 InnoDB, MyISAM 등 원하는 엔진을 자유롭게 교체할 수 있습니다.
Q5. Storage Engine이란 무엇인가요?
스토리지 엔진은 디스크나 메모리와 같은 물리적 저장소에 실제 데이터를 저장하고, 읽어오는 역할을 전담하는 MySQL의 하위 모듈입니다.
상세 설명
- MySQL은 쿼리를 분석하고 최적화하는 Server Layer와 데이터 입출력을 담당하는 Storage Engine Layer가 핸들러 API를 통해 분리된 아키텍처를 가집니다.
- 동일한 SQL 문을 실행하더라도, 어떤 스토리지 엔진을 사용하느냐에 따라 락(Lock)의 범위, 트랜잭션 지원 여부, 인덱스 구조, 복구 방식 등이 완전히 달라집니다.
실무 포인트
- 실무에서는 99% 이상 InnoDB를 사용하지만, 필요에 따라 메모리 기반의 `Memory` 엔진이나 로그 데이터 저장을 위한 `ARCHIVE` 엔진 등을 선택할 수 있다는 아키텍처적 유연성을 이해하고 있으면 좋습니다.
꼬리 질문
- InnoDB 스토리지 엔진의 핵심 내부 구조(Buffer Pool, Redo Log 등)에 대해 아시나요?
- 대표적으로 Buffer Pool, Redo Log가 있습니다. Buffer Pool은 디스크의 데이터와 인덱스를 메모리에 캐싱해 디스크 I/O를 줄여주며, Redo Log는 데이터 변경을 디스크에 선착순 기록(WAL)하여 서버가 다운되어도 데이터를 복구할 수 있게 돕습니다.
- 스토리지 엔진을 테이블 단위로 다르게 지정할 수도 있나요?
- 네. 테이블 생성 시 `ENGINE` 옵션을 통해 개별 지정이 가능합니다. 다만 운영 관리의 복잡성이나 트랜잭션 일관성을 유지하기 위해 최근에는 대부분 InnoDB 하나로 통일하여 사용하는 것을 권장하고 있습니다.
Q6. InnoDB와 MyISAM의 차이를 설명해주세요.
비교표 Summary
| 구분 | InnoDB | MyISAM |
| Transaction | O (ACID 지원) | X |
| Lock Level | Row Level Lock (동시성 높음) | Table Level Lock (동시성 낮음) |
| MVCC | O (동시 읽기/쓰기 향상) | X |
| Foreign Key | O | X |
| Crash Recovery | O (Redo/Undo 로그 활용) | X (데이터 유실 가능성 높음) |
| 주요 용도 | 트랜잭션이 중요한 일반적인 웹 서비스 | 과거 단순 읽기 위주의 블로그/게시판 |
InnoDB는 트랜잭션, Row Level Lock, Foreign Key, Crash Recovery를 지원하여 동시성과 데이터 안전성이 뛰어난 반면, MyISAM은 트랜잭션을 지원하지 않으며 Table Lock을 사용하여 동시성이 떨어집니다.
상세 설명
- InnoDB는 MVCC를 지원하여 읽기 작업과 쓰기 작업이 서로를 대기시키지 않도록 처리합니다.
- 또한 장애 발생 시 Redo Log와 Undo Log를 활용해 트랜잭션의 ACID를 보장하고 데이터를 복구(Crash Recovery)할 수 있습니다.
- 반면 MyISAM은 트랜잭션과 FK가 없으며, 데이터 변경 시 테이블 전체에 락을 걸기 때문에 트랜잭션이 빈번한 현대 웹 애플리케이션에는 적합하지 않습니다.
실무 포인트
- "왜 InnoDB가 기본 엔진이 되었는가?"에 대한 질문에는 "높은 동시성 처리(Row Lock)와 장애 상황에서의 데이터 무결성 보장(Transaction & Recovery)" 두 가지 키워드로 외우는 것이 정석입니다.
꼬리 질문
- Row Level Lock과 Table Level Lock이 성능에 미치는 영향은 무엇인가요?
- Lock 범위를 나타내는 격리성 단위(Granularity)의 차이가 성능에 직결됩니다. Table Level Lock은 구현이 가볍지만 테이블 전체를 잠그기 때문에, 동시성(Concurrency)이 크게 떨어져 CUD 연산이 몰릴 때 병목을 유발합니다.
- Row Level Lock은 잠금 비용은 조금 더 높지만 변경이 일어나는 특정 행만 잠그므로 동시 처리량이 월등히 높아 높은 성능을 냅니다.
- MVCC란 무엇이며, InnoDB에서는 이를 어떻게 구현하나요?
- MVCC(Multi-Version Concurrency Control)는 잠금을 사용하지 않고 동시 읽기/쓰기 성능을 높이는 기술입니다. InnoDB는 Undo Log를 활용해 구현합니다. 데이터를 변경할 때 이전 버전의 데이터를 Undo Log에 보존하고, 읽기 연산 시 스냅샷 기반의 읽기(Consistent Read)를 수행합니다. 이를 통해 `READ` 작업이 `WRITE` 작업의 Lock을 기다리지 않고 빠르게 처리됩니다.
Q7. SQL 구문의 실제 실행 순서는 어떻게 되나요?
작성 순서는 `SELECT - FROM - WHERE - GROUP BY - HAVING -ORDER BY` 이지만, 실제 내부 실행 순서는 `FROM - ON - JOIN -WHERE - GROUP BY - HAVING - SELECT -DISTINCT - ORDER BY - LIMIT` 순서입니다.
상세 설명
- `FROM` / `JOIN` / `ON`: 조회가 일어날 대상 테이블을 지정하고 튜플을 결합합니다.
- `WHERE`: 개별 행(Row)에 대한 필터링 조건 평가를 진행합니다.
- `GROUP BY`: 남은 행들을 그룹화합니다.
- `HAVING`: 그룹화된 결과에 대한 필터링 조건 평가를 진행합니다.
- `SELECT`: 최종 반환할 컬럼들을 추출 및 계산합니다.
- `DISTINCT`: 중복된 결과 값을 제거합니다.
- `ORDER BY`: 추출된 데이터를 정렬합니다.
- `LIMIT`: 출력할 행의 개수를 제한합니다.
실무 포인트
- 실행 순서를 알고 있으면 "WHERE 절에서는 SELECT에서 정의한 Alias(별칭)를 사용할 수 없는 이유"나 "HAVING 절과 WHERE 절의 성능 차이(필터링 시점)"를 명확히 파악할 수 있습니다.
꼬리 질문
- WHERE 절에서 그룹 함수(COUNT, SUM 등)를 사용할 수 없는 이유는 무엇인가요?
- SQL의 실행 순서(Execution Order) 때문입니다. `FROM` → `ON` → `JOIN` → `WHERE` → `GROUP BY` → `HAVING` → `SELECT` → `DISTINCT` → `ORDER BY` → `LIMIT` 순으로 실행됩니다. `WHERE` 절은 집계(Group)가 이루어지기 전에 개별 행(Row) 단위로 필터링하는 단계이므로, 그룹화 이후 생성되는 집계 함수의 결과를 알 수 없어서 사용할 수 없습니다.
- HAVING 절과 WHERE 절 중 성능상 어느 것을 필터링에 먼저 활용하는 것이 유리한가요?
- `WHERE` 절을 통해 사전에 데이터를 필터릴하는 것이 훨씬 유리합니다. `WHERE` 절로 집계 대상이 되는 행의 수를 미리 줄여놓아야 `GROUP BY` 및 메모리 연산 비용을 아낄 수 있습니다. `HAVING` 절은 그룹화가 완료된 후 전체 그룹 결과에 대한 필터링하므로, 처리할 데이터 양 자체가 커져 성능 저하를 일으킵니다.
Q8. 데이터 무결성(Data Integrity)이란 무엇이며, FK는 필수인가요?
데이터 무결성은 DB 내 데이터의 정확성, 일관성, 유효성을 유지하는 것을 의미합니다. Foreign Key는 참조 무결성을 보장하지만, 실무 환경에 따라 DB 레벨의 FK 설정을 생략하기도 합니다.
상세 설명
- 무결성의 종류에는 개체 무결성(PK), 참조 무결성(FK), 도메인 무결성(Data Type, NULL 여부) 등이 있습니다.
- DB 레벨에서 Foregin Key 제약 조건을 걸면 부모 데이터의 삭제 제한, 자식 데이터 삽입 시 검증 등을 통해 강력한 참조 무결성을 보장합니다.
- 그러나 대규모 서비스 환경에서는 FK로 인한 성능 지연(CUD 시, 부모 테이블 락 발생 및 검증 작업), 데드락 발생 가능성, 데이터 마이그레이션 및 파티셔닝의 어려움 때문에 DB FK 제약조건을 제거하고 애플리케이션(Spring) 로직에서 무결성을 검증하는 방식을 많이 채택합니다.
실무 포인트
- 단순히 "FK는 무조건 걸어야 합니다"가 아니라, "참조 무결성을 위해 DB 레벨에서 걸 수도 있지만, 성능 및 동시성, 서비스 확장성을 고려해 애플리케이션 레이어에서 제약조건을 제어하는 경우도 많습니다."라는 유연한 답변이 좋은 평가를 받습니다.
꼬리 질문
- DB 제약조건을 사용하지 않는다면, 애플리케이션 단에서 참조 무결성이 깨지는 것을 어떻게 방지할 수 있나요?
- 크게 세 가지 검증 로직으로 방지할 수 있습니다. 서비스 단 트래잭션 처리, 비즈니스 로직 사전 검증, 비동기 정합성 보정이 있습니다.
Part 2. 데이터 타입
Q9. MySQL 데이터 타입에는 어떠한 것들이 있나요?
MySQL의 데이터 타입은 크게 숫자(Numeric), 문자열(String), 날짜·시간(Date & Time), 이진 데이터(Binary, Spatial)으로 구분됩니다.
상세 설명
- 저장하려는 데이터의 특성과 크기에 맞게 타입을 선택해야 합니다.
- 숫자: `TINYINT`, `SMALLINT`, `INT`, `BIGINT`, `DECIMAL`, `FLOAT`, `DOUBLE` 등이 있습니다.
- 문자열: `CHAR`, `VARCHAR`, `TEXT` 계열(`TEXT`, `MEDIUMTEXT`, `LONGTEXT`), `ENUM` 등이 있습니다.
- 날짜·시간: `DATE`, `TIME`, `DATETIME`, `TIMESTAMP` 등이 있습니다.
- 이진: `BLOB`, `BINARY`, `VARBINARY` 등이 있습니다.
실무 포인트
- 데이터 타입 선택은 단순히 저장되는 문자나 숫자의 형태를 결정하는 것에 그치지 않고, 디스크/메모리 저장 공간 CPU 연산 정확도, 인덱스 크기, 캐시 효율성에 직결됩니다.
- 보통 타입을 나열하는 것보다는 "금액 데이터이므로 `FLOAT` 대신 `DECIMAL`을 사용했습니다."와 같이 선택 기준과 명분을 제시하는 것이 중요합니다.
꼬리 질문
- `DECIMAL`과 `DOUBLE`의 연산 방식 차이는 무엇인가요?
- `DECIMAL`은 고정소수점(Fixed-Point) 방식을 사용하여 숫자를 문자열/정수 배열 형태로 나누어 정확히 연산하므로 오차가 전혀 없는 대신 속도가 상대적으로 느립니다. `DOUBLE`은 부동소수점(Floating-Point) 방식을 사용하여 2진수로 변환해 연산하므로 속도가 빠르지만 미세한 오차가 발생합니다.
- `CHAR`와 `VARCHAR` 중 어떤 상황에 어떤 타입을 선택해야 하나요?
- 데이터의 길이 가변성에 따라 선택합니다. 주민등록번호, UUID, Y/N 여부처럼 길이가 고정된 데이터는 `CHAR`를 사용하여 길이 저장 오버헤드를 줄이고 검색 성능을 높입니다. 반면, 이름, 이메일처럼 길이 변화가 큰 데이터는 `VARCHAR`를 사용하여 실제 저장 공간을 절약합니다.
- `VARCHAR` 대신 `TEXT` 계열을 사용하는 이유는 무엇인가요?
- `TEXT` 계열의 사용 이유는 MySQL의 한 행(Row) 최대 크기 제한(65,535 Bytes)과 메모리 할당 구조 때문입니다. 수천 자 이상의 대용량 텍스트는 `VARCHAR` 크기 한계를 넘기 쉽습니다. 또한 `TEXT`는 실제 데이터가 인라인(Inline) 대신 별도의 오프페이지(Off-page)에 저장되어 행 크기 제한을 우회할 수 있습니다.
- `BLOB`, `BINARY`, `VARBINARY`은 언제 사용하나요?
- 모두 텍스트가 아니라 바이너리(Binary) 데이터(이미지, 파일, 암호화 키 등)를 저장할 때 사용합니다.
- `BINARY`/`VARBINARY`: 상대적으로 작은 크기의 바이너리(암호화된 해시값, IP 주소 등)를 정적/동적 길이로 저장할 때 사용합니다.
- `BLOB`: 대용량 바이너리 파일(이미지, 문서 등)을 저자할 때 사용합니다.
- 모두 텍스트가 아니라 바이너리(Binary) 데이터(이미지, 파일, 암호화 키 등)를 저장할 때 사용합니다.
Q10. CHAR와 VARCHAR의 차이를 설명해주세요.
`CHAR`는 고정 길이 문자열 타입이고, `VARCHAR`는 가변 길이 문자열 타입니다.
상세 설명
- CHAR(Fiexd-length)
- 선언한 길이에 맞춰 항상 고정된 저장 공간을 할당받습니다.
- 길이가 짧은 데이터가 들어오더라도 지정된 크기만큼 공간을 차지합니다.
- 값이 항상 일정하다면 길이 계산이 필요 없어 상대적으로 처리 구조가 단순합니다.
- VARCHAR(Variable-length)
- 실제 입력된 데이터의 길이에 따라 저장 공간이 가변적으로 변합니다.
- 실제 문자열 데이터 외에 데이터의 길이를 나타내는 1~2 Byte의 길이 바이트(Length Prefix)를 추가로 저장합니다.
실무 포인트
- CHAR 사용 권장: 국가코드(`KR`, `US`), 우편번호, 주민등록번호, UUID(36자/HEX 32자), SHA-256 해시값 등 길이가 항상 동일한 식별자 데이터
- VARCHAR 사용 권장: 사용자 이름, 이메일, 주소, 게시글 제목 등 길이가 유동적인 데이터
꼬리 질문
- `VARCHAR`가 무조건 `CHAR`보다 공간 효율적인가요?(길이가 아주 짧고 일정한 경우, 길이 바이트 오버헤드로 인해 오히려 `CHAR`가 유리할 수 있습니다.)
- 그렇지 않습니다. `VARCHAR`는 실제 문자열 외에 데이터 길이를 기록하는 1~2 Byte의 길이 바이트 오버헤드가 추가됩니다. 따라서 `CHAR(1)` 처럼 길이가 매우 짧고 일정한 데이터는 오버헤드가 없는 `CHAR`가 더 공간 효율적입니다.
- `VARCHAR(100)과 `VARCHAR(255)는 저장 공간에 차이가 있나요?
- 디스크 저장 공간에는 차이가 없습니다. 두 타입 모두 실제 입력된 문자열의 길이 + 1 Byte(길이 바이트)만큼만 디스크를 차지합니다. 다만, 쿼리 처리 시 메모리(Temp Table) 상에서는 정의된 최대 길이 기준으로 메모리가 할당될 수 있어 메모리 효율성에는 차이가 납니다.
Q11. VARCHAR와 TEXT의 차이는 무엇인가요?
`VARCHAR`는 메모리(Buffer Pool) 안의 Inline 페이지에 직접 저장되는 비교적 짧은 문자열에 사용하고, `TEXT`는 큰 용량의 본문 데이터를 저장하기 위해 Off-page(오프페이지)에 별도로 저장되는 타입입니다.
상세 설명
- VARCHAR
- 테이블의 최대 행 크기 제한(65,535 Byte) 내에서 작동하며, 인덱스를 생성하기가 매우 용이합니다.
- TEXT
- 최대 64KB(`TEXT`), 16MB(`MEDIUMTEXT`), 4GB(`LONGTEXT`)까지 대용량 텍스트를 저장할 수 있습니다.
- 실제 데이터는 B-Tree 인덱스 블록이 아닌 별도 오프페이지(Off-page) 스토리지 영역에 저장되고, 레코드에는 20 Byte의 포인터만 유지됩니다.
실무 포인트
- `TEXT` 컬럼은 임시 테이블 생성 시 메모리(In-Memory) 임시 테이블이 아닌 디스크 기반 임시 테이블을 사용하게 되어 쿼리 정렬(`ORDER BY`)나 그룹핑(`GROUP BY`) 시 상당한 성능 정하를 유발할 수 있습니다. 따라서 게시글 본문, 상세 설명 등에만 제한적으로 `TEXT`를 사용해야 합니다.
꼬리 질문
- `TEXT` 컬럼에 인덱스를 걸 수 있나요?(Prefix Index를 활용해 앞부분 N자리에만 걸 수 있습니다.)
- 네. Prefix Index(접두사 인덱스)를 통해 가능합니다. `TEXT` 전체 데이터에 인덱스를 걸면 크기가 너무 커지므로, `CREATE INDEX idx_name ON table(text_col(50))`처럼 앞부분 N자리(Prefix)만 지정하여 인덱스를 생성해야 합니다.
- `TEXT` 컬럼이 포함된 테이블을 `SELECT *`로 조회할 때 발생하는 문제는 무엇인가요?
- 오프페이지 읽기로 인한 추가 디스크 I/O 발생으로 성능이 저하됩니다.
- 메모리 임시 테이블(In-Memory Temp Table)을 사용하지 못하고 디스크 임시 테이블(Disk Temp Table)을 생성하게 되어 처리 속도가 급격히 떨어집니다.
Q12. INT와 BIGINT의 차이는 무엇인가요?
`INT`는 4 Byte 정수형으로 약 `-21억 ~ 21억`의 범위를 가지며, `BIGINT`는 8 Byte 정수형으로 약 `-922경 ~ 922경` 범위를 가집니다.
상세 설명
| 구분 | 저장 공간 | Signed 범위 | Unsigned 범위 |
| INT | 4 Byte | 약 -21억 ~ 21억 | 0 ~ 약 42억 |
| BIGINT | 8 Byte | 약 -922경 ~ 922경 | 0 ~ 약 1,844경 |
- Primary Key에 `UNSIGNED` 속성을 주면 음수를 저장하지 않고 0부터 시작하여 표현 범위를 2배로 늘릴 수 있습니다.
실무 포인트
- 지속해서 데이터가 누적되는 핵심 엔티티(회원, 주문, 결제, 로그, 잇기/매핑 테이블 등)의 PK 식별자에는 `BIGINT`를 채택하는 것이 안정합니다.(`INT` 범위를 초과하여 Overflow가 발생하면 서비스 장애로 이어집니다.)
- 다만 모든 컬럼을 `BIGINT`로 도배할 경우, Secondary Index마다 PK(`BIGINT`) 정보가 포함되므로 메모리와 디스크 공간이 불필요하게 낭비될 수 있습니다.
꼬리 질문
- `INT UNSIGNED`로 충분한 테이블과 그렇지 않은 테이블의 기준은 무엇인가요?
- 음수 데이터 필요 여부와 데이터의 예상 증가량(21억 vs 42억)이 기준입니다.
- INT UNSIGNED: 음수가 절대 없고(예: PK, 나이, 조회수, 포인트) 최대 약 42억 건까지 수용하고 싶을 때 사용합니다.
- 그렇지 않은 경우: 온도/좌표 등 음수 표현이 필요한 경우는 SIGNED를, 데이터가 42억 건을 넘을 가능성이 높다면(예: 대규모 로그, 결제 내역) BIGINT를 사용해야 합니다.
- 음수 데이터 필요 여부와 데이터의 예상 증가량(21억 vs 42억)이 기준입니다.
- PK의 값이 Overflow 되어 초과하면 어떤 오류가 발생하나요?
Q13. FLOAT, DOUBLE, DECIMAL의 차이는 무엇인가요?
`FLOAT`, `DOUBLE`은 부동소수점 방식을 사용하여 근사값을 저장하고, `DECIAML`은 고정 소수점 방식을 사용하여 오차 없이 정확한 십진수 숫자를 저장합니다.
상세 설명
- `FLOAT`/`DOUBLE`
- 이진 부동소수점 표현법(IEEE 754 표준)을 따르므로 저장 공간은 적고 연산 속돈느 빠르지만, 소수점 이하 계산 시 부동소수점 오차가 발생합니다.
- `DECIMAL`
- 숫자를 문자열과 유사한 방식으로 정밀하게 분할 저장하는 고정소수점 타입입니다.
- `DECIAML(12, 2) 형태롤 선언 시 전체 12자리 중 소수점 이하 2자리를 오차 없이 정확하게 보장합니다.
실무 포인트
- 금융, 결제, 수수료, 포인트, 비율 등 정밀한 계산이 필요한 수치 데이터에는 반드시 `DECIMAL`을 사용해야 합니다.
- 소수점이 필요 없는 원화(KRW) 결제 시스템의 경우 `DECIMAL` 대신 `BIGINT`(원 단위 정수)로 저장하는 방식도 실무에서 널리 활용됩니다.
꼬리 질문
- 부동소수점 오차가 발생하는 근본적인 원인은 무엇인가요?
- `DECIAML` 타입 연산이 `DOUBLE` 연산보다 느린 이유는 무엇인가요?
- `FLOAT`, `DOUBLE`, `DECIMAL` 타입이 나타낼 수 있는 숫자 범위는 무엇인가요?
Q14. DATETIME과 TIMESTAMP의 차이를 설명해주세요.
`DATETIME`은 시간대 변환 없이 입력된 날짜와 시간 형태를 그대로 저장하며, `TIMESTAMP`는 입력값을 UTC 기준 시각으로 변환하여 저장한 뒤 조화 시 세션 시간대에 맞게 보여줍니다.
상세 설명
| 구분 | DATETIME | TIMESTAMP |
| 저장 공간 | 5 Byte (fsp 포함 시 최대 8 Byte) | 4 Byte (fsp 포함 시 최대 7 Byte) |
| 저장 범위 | `1000-01-01 ~ 9999-12-31` | `1970-01-01 ~ 2038-01-19` (Year 2038 문제) |
| Timezone 변환 | 변환되지 않음 (입력값 그대로 저장) | 저장 시 UTC 변환 / 조회 시 세션 Timezone 적용 |
| 주요 용도 | 생년월일, 결제 예약 시각 등 absolute 시각 | 데이터 생성/수정 시각(created_at, updated_at) |
실무 포인트
- 글로벌 서비스이거나 여러 지역에 서버/DB가 분산된 환경이라면 `TIMESTAMP` 또는 Application 단에서 UTC로 일일이 변환하여 `DATETIME`에 저장하는 방식을 고민해야 합니다.
- `TIMESTAMP` 사용 시 2038년 제한(Year 2038 Problem)이 존재하므로, 최근 MySQL 8.0 이상 환경에서는 넓은 표현 범위를 가지는 `DATETIME`을 표준으로 채택하는 추세도 강합니다.
꼬리 질문
- MySQL의 `time_zone` 세션 설정을 변경하면 기존에 들어왔던 `DATETIME`과 `TIMESTAMP` 데이터는 각각 어떻게 다르게 조회되나요?
- Spring Boot(JVM) 시간대와 MySQL DB 시간대가 다를 때 발생하는 문제와 해결법은 무엇인가요?
Q15. NULL이란 무엇인가요?
`NULL`은 숫자 `0`이나 빈 문자열 `''`과 다르게, "값이 존재하지 않음" 또는 "알 수 없음(Unknown)"을 나타내는 특수한 상태입니다.
상세 설명
- SQL 연산에서 `NULL`이 포함된 연산은 3값 논리(True, False, Unknown)으로 평가됩니다.
- `NULL`은 `=` 연산자로 비교할 수 없습니다. 반드시 `IS NULL` 또는 `IS NOT NULL`을 사용해야 합니다.(`NULL = NULL`의 결과조차 True가 아니라 `Unknown`입니다.)
- 집계함수(`COUNT(column)`, `AVG`, `SUM` 등)에서 `NULL` 값은 기본적으로 계산 대상에서 제외됩니다.(단, `COUNT(*)`는 행 전체 개수를 세므로 제외되지 않습니다.)
실무 포인트
- 가능하면 컬럼 설계 시 `NOT NULL` 제약조건과 Default 값을 설정하는 것을 권장합니다.
- 컬럼에 `NULL`이 허용되면 인덱스 탐색 방식이 복잡해지고, 애플리케이션(Java) 레이어에서 `NullPointerException(NPE)` 핸들링 코드가 과도하게 늘어나는 부작용이 존재합니다.
꼬리 질문
- `COUNT(*)와 `COUNT(column_name)`의 연산 결과 차이는 무엇인가요?
- `NULL` 컬럼에도 인덱스가 정상적으로 작동되어 동작하나요?
- `NULL` 이 존재하는 데이터의 개수를 세는 쿼리문은 무엇인가요?
- `NULL` 이 존재하지 않는 데이터의 개수를 세는 쿼리문은 무엇인가요?
Q16. `VARCHAR(50)`과 `VARCHAR(255)`의 성능 차이가 있나요?
디스크 저장 공간에는 차이가 없지만, 메모리(Buffer Pool 및 Temporary Table) 사용 영역에서 차이가 발생합니다.
상세 설명
- 디스크에 데이터를 보관할 때는 실제 입력된 데이터의 길이만큼만 저장하므로 `VARCHAR(50)`과 `VARCHAR(255)`에 `'hello'`를 똑같이 저장하면 동일한 용량을 차지합니다.
- 그러나 쿼리를 처리할 때(인메모리 임시 테이블을 다루거나 정렬/그룹핑 수행 시) MySQL은 컬럼에 정의된 최대 가상 크기만큼의 메모리 공간을 고정 할당합니다.
실무 포인트
- 넉넉하게 적는다고 무작정 `VARCHAR(255)`를 남발하면, 복잡한 쿼리가 실행될 때 메모리 낭비가 심해져 디스크 임시 테이블로 전환(Disk I/O)될 위험이 높아집니다.
- 따라서 실제 비즈니스 도메인에 알맞는 길이로 상한선으로 지정하는 것을 권장합니다.
꼬리 질문
- `VARCHAR`의 길이를 255이하로 잡는 것과 256이상으로 잡는 것에 구조적 차이가 있나요?(길이 바이트가 1 Byte에서 2 Byte로 늘어납니다.)
Q17. ENUM 타입이란 무엇이며, 실무에서 추천하나요?
`ENUM`은 정해진 문자열 목록 중 하나만 선택하여 내부적으로 정수(`1, 2, 3, ...`) 매핑으로 저장하는 타입입니다. 공간 절약에는 유용하지만, 유연성과 확장성 떨어짐 때문에 실무에서는 사용을 지양하는 편입니다.
상세 설명
- 장점: 문자열 형태로 표기되지만 내부적으로 1~2 Byte의 정수로 저장되어 디스크 공간을 아낄 수 있습니다.
- 단점: 새로운 상태값이 추가될 때마다 `ALTER TABLE`을 실행해야 하므로 DDL 비용이 발생합니다. 또한 정수형 인덱스 정렬 시 직관적이지 않은 동작을 유발합니다.
실무 포인트
- 실무에서는 상태값을 저장할 때 `ENUM` 대신 `VARCHAR` + 애플리케이션 ENUM(Spring Java enum)을 조합하거나, 공통 공정 코드 테이블(Ref Table)을 별도로 분리하여 외래 키로 참조하는 방식을 훨씬 선호합니다.
꼬리 질문
- `ENUM` 타입 컬럼에 새로운 항목을 추가할 때 발생할 수 있는 데이터베이스 이슈는 무엇인가요?
'🐬MySQL' 카테고리의 다른 글
| MySQL: useSSL의 대안 sslMode (0) | 2025.10.21 |
|---|
