장애 회의에서 DBA가 빠르게 말합니다. "슬로우 쿼리가 Full Scan 타고, 거기에 Deadlock까지 겹쳤어요. N+1도 의심되고, Replica 복제 지연으로 방금 쓴 데이터가 안 보인대요." PM·인프라인 당신은 이 말들이 각각 얼마나 심각한지, 무엇을 해야 하는지 판단해야 합니다. 이 사전은 DB·SQL 실무 용어를 빠르게 해독하고 대응 방향을 잡게 합니다. 깊은 진단은 Database 트랙의 심화 모듈로 연결합니다.
- 1트랜잭션·격리수준·잠금/데드락 용어를 듣고 심각도를 가늠할 수 있다
- 2인덱스·실행계획·Full Scan·N+1로 성능 문제 방향을 잡을 수 있다
- 3복제·샤딩·페일오버로 가용성/확장 구조를 이해할 수 있다
- 4DDL/DML/TCL과 JOIN 종류로 SQL 대화를 따라갈 수 있다
트랜잭션 · 잠금 · 격리
데이터 정합성을 지키는 메커니즘
| 용어 | 한 줄 뜻 | 신호/대응 | 중요도 |
|---|---|---|---|
| Transaction / Commit / Rollback | 한 묶음 작업 / 확정 / 취소 | 부분 실패 시 롤백 | ★★★ |
| Lock | 동시 변경을 막는 잠금 | 과하면 대기·데드락 | ★★ |
| Deadlock | 서로의 락을 기다려 멈춤 | 잠금 순서 일관화로 예방 → 트랜잭션 격리 수준(Isolation Level)과 이상 현상 제어 | ★★ |
| Isolation Level | 동시성 격리 수준 | RC/RR/Serializable | ★★ |
| Read Committed / Repeatable Read / Serializable | 격리 수준 3종 | PG 기본 RC, MySQL 기본 RR | ★★ |
| Dirty Read / Phantom Read | 이상 현상(미커밋 읽기 / 행수 변화) | 격리 수준으로 방지 | ★★ |
핵심: 격리수준·이상현상·데드락의 깊은 내용은 트랜잭션 격리 수준(Isolation Level)과 이상 현상 제어에서 다룹니다. PM은 "Serializable로 올리면 안전하지만 느려진다"는 트레이드오프만 알면 됩니다.
확대
위 그림처럼 격리수준이 높아질수록 이상현상은 줄지만 동시성(성능)이 떨어집니다. MySQL 기본은 Repeatable Read, PostgreSQL 기본은 Read Committed입니다.
성능 — 인덱스·실행계획·N+1
느린 쿼리의 언어
| 용어 | 한 줄 뜻 | 신호/대응 | 중요도 |
|---|---|---|---|
| Slow Query | 느린 쿼리 | 실행계획부터 확인 | ★★★ |
| Query/Execution Plan | DB의 쿼리 실행 방법 | EXPLAIN으로 확인 → 쿼리 실행 계획(Execution Plan) 읽는 법과 인덱스 최적화 | ★★★ |
| Full Scan / Index Scan | 전체 읽기 / 인덱스 읽기 | type:ALL=Full=느림 신호 | ★★★ |
| Index / Composite Index | 인덱스 / 복합 인덱스 | 등치조건 앞·범위 뒤 → B-Tree 인덱스의 작동 원리와 인덱스 설계의 핵심 조건 | ★★★ |
| PK / FK / Unique / Constraint | 기본키/외래키/유니크/제약 | 데이터 무결성 | ★★ |
| N+1 Problem | 연관 조회가 N번 추가로 나감 | eager loading → Prisma, JPA, TypeORM, SQLAlchemy의 성능 차이와 올바른 사용법 | ★★★ |
| Connection/Read/Query Timeout | 접속/읽기/쿼리 타임아웃 | 슬로우쿼리·풀고갈 동반 | ★★ |
핵심: "Full Scan"이 보이면 인덱스 부재 신호. "N+1"은 ORM 목록 조회의 단골 함정. 둘 다 쿼리 실행 계획(Execution Plan) 읽는 법과 인덱스 최적화·Prisma, JPA, TypeORM, SQLAlchemy의 성능 차이와 올바른 사용법에서 깊이 다룹니다.
확대
위 그림처럼 인덱스가 있으면 B-Tree를 따라 단 몇 번의 I/O로 원하는 행에 도달합니다. EXPLAIN 결과에서 type: ALL은 Full Scan 신호이며 인덱스 추가가 1순위 대응입니다.
가용성·확장 — 복제·샤딩·백업
DB를 늘리고 지키는 구조
| 용어 | 한 줄 뜻 | 비고 | 중요도 |
|---|---|---|---|
| Replication / Master-Slave / Primary-Replica | 복제 / 쓰기-읽기 분리 | 읽기 분산·페일오버 → Master-Slave 복제(Replication) 구축과 DB 고가용성(HA) 아키텍처 | ★★ |
| Failover | 장애 시 대체로 전환 | Replica 승격 | ★★ |
| Sharding / Partition | 데이터를 쪼개 분산 / 분할 | 대용량 확장 | ★★ |
| Backup / Restore / Dump | 백업 / 복원 / 덤프 | 재해복구 기본 → 파일/설정/DB 백업과 재해복구 기초 | ★★★ |
| Migration / DDL / DML / DCL / TCL | 스키마 변경 / 정의·조작·제어·트랜잭션 SQL | 안전 배포 → Flyway와 Liquibase를 이용한 DB 마이그레이션 버전 관리 | ★★ |
| Sequence / Auto Increment | 자동 증가 ID | UUID 대비 → InnoDB 스토리지 엔진 구조와 한글 인코딩, Auto Increment | ★ |
| Trigger / Procedure / Function / View / Materialized View | DB 측 로직/뷰 | 캐싱·자동화 → 뷰(View)와 Stored Procedure의 운영 관점 장단점 | ★ |
확대
위 그림처럼 쓰기는 Primary 한 곳으로, 읽기는 여러 Replica로 분산해 부하를 낮춥니다. Primary 장애 시 Replica를 승격(Failover)하지만, 복제 지연으로 인해 방금 쓴 데이터가 Replica에서 안 보일 수 있으므로 읽기 일관성이 중요한 경우 Primary에서 읽어야 합니다.
JOIN·서브쿼리·배치
조회와 대량 처리 용어
| 용어 | 한 줄 뜻 | 비고 | 중요도 |
|---|---|---|---|
| Inner / Left / Right / Outer Join | 교집합 / 왼쪽보존 / 오른쪽보존 / 전체 | 누락 버그 주의 → INNER, LEFT, RIGHT, FULL JOIN의 최적화 실행 조건 | ★★ |
| Subquery / CTE / Cursor | 중첩쿼리 / WITH절 / 커서 | 가독성·성능 → 서브쿼리와 CTE(WITH 문)를 활용한 쿼리 구조화 | ★ |
| Batch Insert/Update / Upsert | 대량 삽입·수정 / 있으면수정없으면삽입 | 성능 → 대량 데이터 고성능 처리 패턴 Bulk Insert·Update·Delete | ★★ |
| Pagination / Offset / Limit | 페이지 처리 | 큰 offset 느림 주의 | ★★ |
핵심: INNER vs LEFT JOIN을 혼동하면 "신규 회원이 보고서에서 누락"되는 버그가 납니다(INNER, LEFT, RIGHT, FULL JOIN의 최적화 실행 조건). PM이 데이터 요구를 적을 때 "주문 없는 회원도 포함?"을 명시하면 이 혼동을 막습니다.
장애 로그에서 DB 용어 해독 — 직접 확인
DB 관련 로그/에러가 보이면 그 용어 자체가 대응 방향의 단서입니다.
grep -iE 'deadlock|lock wait timeout|slow query|connection timeout' app.log | tail
ERROR Deadlock found when trying to get lock (MySQL 1213)
→ 데드락. 잠금 순서 일관화·트랜잭션 짧게([[transaction-isolation]])
WARN Slow query 4.2s: SELECT * FROM orders WHERE status=...
→ 실행계획 확인, status 인덱스 검토([[query-execution-plan]])
ERROR Lock wait timeout exceeded (MySQL 1205)
→ 다른 트랜잭션이 락 오래 점유. 슬로우쿼리/미커밋 트랜잭션 의심
grep -iE 'deadlock|timeout|slow|lock wait' app.log | tail- "Deadlock found(1213)"는 보통 DB가 한쪽을 죽여 자동 복구 → 빈도가 높으면 잠금 순서·트랜잭션 길이 문제(트랜잭션 격리 수준(Isolation Level)과 이상 현상 제어)
- "Slow query Ns"에서 N이 수 초면 실행계획부터: type:ALL(Full Scan)이면 인덱스 추가가 1순위(쿼리 실행 계획(Execution Plan) 읽는 법과 인덱스 최적화)
- "Lock wait timeout(1205)"은 다른 트랜잭션이 락을 오래 쥔 것 → 미커밋 트랜잭션·슬로우쿼리가 원인. 커넥션 상태도 함께 확인(DB 연결 지연을 없애는 HikariCP 설정과 대기 성능 튜닝)
- 복제 지연으로 "방금 쓴 데이터가 안 보임"이면 읽기를 Replica가 아닌 Primary로 보내거나 일관성 요구를 재검토(Master-Slave 복제(Replication) 구축과 DB 고가용성(HA) 아키텍처)
상황: 회원·주문 목록 화면이 데이터가 늘면서 급격히 느려집니다. DB 슬로우 로그엔 비슷한 작은 쿼리가 수백 개씩 반복됩니다.
원인: N+1 문제입니다. 목록 N건을 가져온 뒤 각 항목의 연관 데이터(작성자·상품 등)를 1건씩 추가 조회해 총 N+1번 쿼리가 나갑니다. ORM의 지연 로딩(lazy loading)에서 흔합니다(Prisma, JPA, TypeORM, SQLAlchemy의 성능 차이와 올바른 사용법).
진단:
# 같은 형태의 작은 쿼리가 반복되는지(N+1 신호)
grep "SELECT .* FROM authors WHERE id" app.log | wc -l # 수십~수백이면 N+1
해결: eager loading(JOIN으로 한 번에)으로 N+1을 1~2번 쿼리로 줄입니다(JPA join fetch/@EntityGraph, SQLAlchemy joinedload). 깊은 내용은 Prisma, JPA, TypeORM, SQLAlchemy의 성능 차이와 올바른 사용법. PM·인프라는 "목록 화면이 데이터 늘며 느려진다"는 증상에서 N+1을 1순위로 의심해, 개발팀에 eager loading 적용을 요청하도록 방향을 잡습니다.
심화 — 느린 쿼리는 혼자 죽지 않는다
심화: 용어들이 연쇄되는 경로 — 알람이 울린 곳에 범인이 없다
이 사전의 용어들은 장애 현장에 낱개로 오지 않고 사슬로 옵니다. 사슬을 알면 알람이 울린 지점이 아니라 사슬의 첫 고리를 찾게 됩니다.
- 장애의 표준 연쇄: Slow Query → 그 쿼리가 락을 오래 점유 → 다른 트랜잭션들이 Lock wait timeout → 대기하는 커넥션이 쌓여 커넥션 풀 고갈(DB 연결 지연을 없애는 HikariCP 설정과 대기 성능 튜닝) → DB와 무관해 보이는 API까지 전부 타임아웃. 알람은 맨 끝(풀 고갈)에서 울리지만 근원은 맨 앞의 쿼리 하나입니다. 풀 크기만 늘리면 근원을 놓친 채 폭발 시점만 늦춥니다.
- 면접의 다음 질문 — "그 인덱스, 어떻게 추가할 건데요?": 인덱스 추가가 답인 걸 아는 것과, 운영 중인 수천만 행 테이블에 추가할 줄 아는 것은 다른 역량입니다. DDL 자체가 락과 부하를 일으키므로, online DDL 지원 여부·점검 시간대·복제 지연 영향까지 판단해 실행하는 것이 실무의 답입니다(Flyway와 Liquibase를 이용한 DB 마이그레이션 버전 관리).
- "트랜잭션은 짧게"의 실전 번역: 트랜잭션 안에서 외부 API 호출·파일 처리를 하면 그 응답을 기다리는 내내 락을 쥔 채입니다. 외부 API가 5초 느려지는 순간 락 대기가 5초씩 늘며 위의 연쇄가 시작됩니다 — "트랜잭션 안에는 DB 작업만"이 이 사슬을 끊는 원칙입니다(트랜잭션 격리 수준(Isolation Level)과 이상 현상 제어).
- 데드락 빈도는 품질 지표입니다: 데드락은 DB가 한쪽을 죽여 자동 복구되므로 가끔 한 건은 정상 운영의 일부입니다. 그러나 빈도가 늘었다면 '같은 자원을 다른 순서로 잡는 코드'가 새로 들어왔다는 신호입니다 — 건수 추이를 지표로 보는 팀과 에러 로그로 흘려보내는 팀의 차이가 여기서 갈립니다.
용어를 낱개로 알면 알람마다 따로 대응하고, 사슬로 알면 첫 고리를 찾습니다. 장애 회의에서 "풀 고갈이니 풀을 늘리자"를 "그 전에 어떤 쿼리가 락을 쥐고 있었나"로 바꾸는 것이 이 사전의 심화입니다.
상황: '컬럼 하나 추가라 금방 끝난다'며 업무 시간에 주문 테이블에 ALTER TABLE을 실행했습니다. 몇 초 뒤부터 그 테이블을 읽는 화면 전체가 멈추고, 타임아웃이 서비스 전반으로 번집니다.
원인: ALTER는 시작하려면 메타데이터 락(MDL)이 필요한데, 마침 오래 열려 있던 미커밋 트랜잭션 하나가 그 테이블을 잡고 있었습니다. ALTER는 그 트랜잭션이 끝나길 기다리며 줄을 서고, 진짜 문제는 그 뒤에 오는 모든 쿼리(단순 SELECT 포함)가 ALTER 뒤에 줄을 선다는 것입니다. '기다리는 중인 DDL' 하나가 테이블 전체를 볼모로 잡는 구조입니다.
진단:
SHOW PROCESSLIST;
-- State 컬럼에 Waiting for table metadata lock 이 다수면 확정
-- 줄의 맨 앞을 찾는다: 오래 실행 중이거나 미커밋 상태의 트랜잭션
해결: (1) 급한 불 — 맨 앞의 오래된 트랜잭션(또는 ALTER 자체)을 kill해 줄을 풉니다. (2) 재발 방지 — 대형 테이블 DDL은 online DDL·점검 시간대에 수행하고, 실행 전 장기 트랜잭션이 없는지 확인하는 절차를 마이그레이션 체크리스트에 넣습니다(Flyway와 Liquibase를 이용한 DB 마이그레이션 버전 관리). (3) DDL 세션에 짧은 lock_wait_timeout을 걸어, 락을 못 잡으면 서비스를 세우는 대신 DDL이 포기하게 만듭니다. '작은 변경'의 크기는 코드 diff가 아니라 락의 파급 범위로 재야 합니다.
인프라/SRE로서 DB 용어는 모니터링·장애 대응의 핵심입니다 — 슬로우 쿼리·데드락·복제 지연·커넥션 풀을 대시보드(용어사전)로 보고, 임계 초과 시 이 사전이 의심 방향을 알려줍니다. 깊은 진단은 Database 트랙(transaction-isolation·query-execution-plan·connection-pooling·replication-ha)으로 이어집니다. PM은 이 용어를 알면 "DB가 느리다"는 모호한 보고를 "특정 쿼리 인덱스 부재 / N+1 / 복제 지연" 같은 구체적 원인으로 좁혀, 재발 방지를 백로그 우선순위로 올릴 수 있습니다.
다음 용어사전에서는 서비스 간 통신과 인증 — API·인증/인가 용어를 정리합니다.
용어 식별 실습으로 굳히기: 용어 식별 — DB / SQL — 증상을 보고 트랜잭션·N+1·복제 같은 용어를 가려내고 헷갈리는 짝을 구분합니다.