모던지 / 정보처리기사 / 데이터베이스 구축 3강. 물리 설계와 인덱스·트랜잭션

데이터베이스 구축 3강. 물리 설계와 인덱스·트랜잭션

은행 계좌 이체 도중에 정전이 나면 돈은 어디에 있을까요. 이 질문에 답하기 위해 트랜잭션이라는 개념이 만들어졌습니다.

풀고 시작

문제 1. 트랜잭션의 특성 중, 트랜잭션의 연산이 모두 반영되거나 전혀 반영되지 않아야 한다는 성질은?
전부 아니면 전무를 뜻하는 것이 원자성입니다. 일관성은 실행 전후로 데이터베이스가 모순 없는 상태를 유지해야 한다는 것, 격리성은 수행 중 다른 트랜잭션이 끼어들 수 없다는 것, 지속성은 완료된 결과가 영구히 보존된다는 것입니다.

물리 설계는 저장 장치와의 협상입니다

논리 설계가 끝나면 실제 저장 구조를 정합니다. 어떤 자료형을 쓸지, 어떤 컬럼에 인덱스를 걸지, 파일을 어떻게 배치할지, 용량은 얼마나 잡을지를 결정하는 단계죠. 논리 설계가 "무엇을 저장할까"라면 물리 설계는 "어떻게 빨리 꺼낼까"입니다.

물리 설계에서 가장 중요한 결정이 인덱스입니다. 책 뒤의 찾아보기와 같습니다. 인덱스가 없으면 원하는 값을 찾기 위해 표를 처음부터 끝까지 훑어야 합니다(전체 테이블 스캔). 인덱스가 있으면 정렬된 색인을 타고 바로 갈 수 있죠.

구조로는 B트리 인덱스가 표준입니다. 균형 잡힌 트리라 어느 값을 찾아도 비슷한 깊이만 내려가면 됩니다. 비트맵 인덱스는 값의 종류가 적은 컬럼, 예컨대 성별이나 상태 코드에 유리합니다. 해시 인덱스는 정확히 일치하는 값을 찾을 때는 빠르지만 범위 조회에는 쓸 수 없습니다.

인덱스에는 대가가 있습니다. 조회는 빨라지지만 삽입·수정·삭제는 느려집니다. 데이터가 바뀔 때마다 인덱스도 함께 갱신해야 하니까요. 저장 공간도 추가로 듭니다. 그래서 "일단 다 걸어 두자"는 접근은 틀렸습니다. 조건절과 조인, 정렬에 자주 쓰이는 컬럼에 선별적으로 겁니다.

트랜잭션의 네 글자, ACID

계좌 A에서 B로 10만 원을 옮긴다고 합시다. A에서 빼고 B에 더하는 두 연산 사이에 정전이 나면 돈이 증발합니다. 이 사고를 막기 위해 트랜잭션은 여러 연산을 하나의 논리적 작업 단위로 묶습니다.

특성
원자성 (Atomicity) 전부 반영되거나 전혀 반영되지 않는다
일관성 (Consistency) 실행 전후로 데이터베이스가 모순 없는 상태를 유지한다
격리성 (Isolation) 수행 중인 트랜잭션에 다른 트랜잭션이 끼어들 수 없다
지속성 (Durability) 성공적으로 완료된 결과는 영구히 보존된다

트랜잭션의 상태도 자주 나옵니다. 실행을 시작한 활동, 마지막 연산까지 끝낸 부분 완료, 결과를 확정한 완료, 오류로 중단된 실패, 그리고 시작 이전으로 되돌린 철회입니다. 결과를 확정하는 명령이 COMMIT, 되돌리는 명령이 ROLLBACK입니다.

동시성 제어는 순서를 지켜 주는 일입니다

여러 트랜잭션이 동시에 같은 데이터를 건드리면 문제가 생깁니다. 갱신 손실은 두 트랜잭션이 같은 값을 고쳐 한쪽 결과가 사라지는 현상, 오손 읽기(dirty read)는 아직 확정되지 않은 값을 다른 트랜잭션이 읽는 현상, 모순성은 한 트랜잭션이 같은 값을 두 번 읽었는데 결과가 다른 현상입니다.

해결책의 기본은 로킹(locking)입니다. 데이터를 쓰기 전에 잠그고, 끝나면 풉니다. 잠그는 단위를 로킹 단위라고 하는데, 단위가 크면 관리가 쉬운 대신 동시성이 떨어지고, 단위가 작으면 동시성이 올라가는 대신 관리 부담이 커집니다. 이 맞교환이 그대로 문제로 나옵니다.

2단계 로킹 규약은 잠금을 얻기만 하는 확장 단계와 풀기만 하는 축소 단계로 나눕니다. 이렇게 하면 직렬 가능성이 보장되지만, 서로가 서로의 잠금을 기다리는 교착 상태(deadlock)가 생길 수 있습니다. 교착 상태를 다루는 방법은 예방, 회피, 탐지와 회복으로 나뉩니다.

타임스탬프 순서 규약은 다른 접근입니다. 트랜잭션마다 도착 시각을 붙여 두고 그 순서대로 처리하게 강제하므로 교착 상태가 아예 생기지 않습니다. 대신 순서를 어긴 트랜잭션은 철회되고 다시 시작해야 합니다.

회복은 로그가 있어야 가능합니다

장애가 나면 데이터베이스를 정상 상태로 되돌려야 합니다. 이때 쓰는 것이 로그입니다. 무엇을 어떻게 바꿨는지 기록해 두었다가, 완료된 트랜잭션은 다시 반영하고(REDO), 완료되지 못한 트랜잭션은 되돌립니다(UNDO).

즉시 갱신 기법은 변경을 곧바로 데이터베이스에 반영하므로 회복 시 REDO와 UNDO가 모두 필요합니다. 지연 갱신 기법은 커밋 전까지 실제 반영을 미루므로 UNDO가 필요 없습니다. 그 외에 특정 시점의 상태를 통째로 저장해 두는 검사점 기법그림자 페이징 기법이 있습니다.

다음 강에서는 이 데이터베이스를 실제로 다루는 언어, SQL로 들어갑니다.

인출 문제

문제 1. 인덱스에 대한 설명으로 옳지 않은 것은?
비트맵 인덱스는 성별이나 상태 코드처럼 값의 종류가 적을 때 유리합니다. 값의 가짓수가 많으면 비트맵이 커져 오히려 비효율적이라 B트리 쪽이 적합합니다.
문제 2. 아직 커밋되지 않은 다른 트랜잭션의 변경 값을 읽어 발생하는 문제는?
확정되지 않은 값을 읽는 것이 오손 읽기입니다. 갱신 손실은 동시에 수정해 한쪽 결과가 사라지는 현상이고, 교착 상태는 서로의 잠금을 기다리며 멈춘 상황이며, 연쇄 복귀는 한 트랜잭션의 철회가 다른 트랜잭션의 철회를 부르는 현상입니다.
문제 3. 트랜잭션의 격리성에 대한 설명으로 옳은 것은?
격리성은 다른 트랜잭션이 중간 상태를 들여다볼 수 없게 하는 성질입니다. 첫 보기는 지속성, 둘째는 원자성, 넷째는 일관성의 설명이므로 네 특성을 짝지어 정리해 두시는 편이 좋습니다.
문제 4. 회복 기법 중 지연 갱신 기법의 특징으로 옳은 것은?
지연 갱신은 커밋 시점까지 실제 반영을 미루기 때문에 철회할 것이 없어 UNDO가 불필요합니다. 즉시 반영하며 REDO와 UNDO를 모두 쓰는 것은 즉시 갱신 기법이고, 두 기법 모두 로그는 기록합니다.

생각해볼 질문 (정답 없음)

동시성을 높이려면 잠금을 잘게 걸어야 하고, 안전을 높이려면 크게 걸어야 합니다. 어떤 서비스에서 어느 쪽으로 기울이시겠습니까. 그 판단은 무엇을 측정해야 정당해질까요.


이전: 2강 정규화와 이상 현상 · 다음: 4강 SQL DDL과 DML

모던지 · 궁금하면 모던지 GitHub · 2026-09-10