프로그래밍데이터 엔지니어

SQL에서 트랜잭션 격리 원칙(isolation levels)과 애플리케이션에 적합한 격리 수준을 선택하는 방법을 설명하십시오. 각 수준에 대한 비정상 현상의 예를 제시하십시오.

Hintsage AI 어시스턴트로 면접 통과

답변

트랜잭션 격리는 동시에 실행되는 트랜잭션이 서로의 변경 사항을 어떻게 보는지를 결정합니다. 이는 ACID 속성의 중요한 부분입니다. ANSI SQL에는 네 가지 기본 격리 수준이 있습니다:

  • READ UNCOMMITTED — 다른 트랜잭션의 커밋되지 않은 변경 사항도 볼 수 있습니다(더러운 읽기, dirty reads).
  • READ COMMITTED — 커밋된 변경 사항만 볼 수 있으며, 더러운 읽기를 방지하지만 비반복 읽기(non-repeatable reads)는 허용됩니다.
  • REPEATABLE READ — 동일한 트랜잭션 내에서 동일한 데이터가 변하지 않게 보입니다. 더러운 읽기와 비반복 읽기를 피하지만 팬텀 읽기(phantom reads)가 발생할 수 있습니다.
  • SERIALIZABLE — 가장 엄격한 수준으로, 트랜잭션이 완전히 격리되어 마치 순차적으로 실행되는 것처럼 보입니다. 모든 종류의 비정상 현상을 제거합니다.

수준 선택은 애플리케이션의 요구 사항에 따라 다릅니다:

  • 보고용으로는 보통 REPEATABLE READ 이상이면 충분합니다;
  • 고부하 시스템에는 최적의 절충안은 READ COMMITTED입니다;
  • 금융 거래의 경우 SERIALIZABLE이지만 성능 저하가 불가피합니다.

예제:

SET TRANSACTION ISOLATION LEVEL REPEATABLE READ; BEGIN; -- 이후의 SELECT는 "고정된" 값을 볼 것입니다.

함정 질문

"REPEATABLE READ 수준이 모든 DB에서 팬텀 읽기로부터 보호를 보장합니까?"

아닙니다. PostgreSQL 및 일부 다른 DBMS에서는 REPEATABLE READ 수준이 더러운 읽기와 비반복 읽기만 방지하고 팬텀 읽기로부터 반드시 보호하지는 않습니다. MySQL/InnoDB에서 REPEATABLE READ는 사실상 SERIALIZABLE이지만, 다른 DBMS에서는 그렇지 않습니다.

예제:
-- 하나의 트랜잭션에서 SELECT * FROM orders WHERE amount > 100을 읽습니다; -- 다른 트랜잭션에서 amount > 100인 새로운 값을 삽입하고 커밋합니다. -- 첫 번째 트랜잭션이 반복 SELECT를 할 때 SERIALIZABLE 미만의 격리로 "팬텀" 행을 볼 수 있습니다.

주제에 대한 이해 부족으로 인한 실제 오류 사례


이야기

금융 서비스가 성능을 이유로 READ COMMITTED로만 설정하여 사용자가 다른 프로세스에 의해 이미 변경된 금액을 보게 되었고, 잔액 불일치가 발생했습니다.


이야기

호텔 예약 시스템에서 같은 방에 대한 이중 예약이 발생했습니다 — 트랜잭션이 현재 예약의 수출을 격리하지 않았고, 수준은 READ COMMITTED였습니다.


이야기

MySQL에서 PostgreSQL로의 전환: 개발자는 REPEATABLE READ가 팬텀으로부터 보호한다고 믿었지만, 마이그레이션 후 동일한 트랜잭션 내에서 반복 요청 시 예상치 못한 "보류" 주문이 나타났습니다.