트랜잭션
트랜잭션(transaction)은 데이터베이스의 상태를 바꾸기 위해 수행하는 작업의 단위 또는 일련의 연산을 의미한다.
데이터베이스의 트랜잭션은 ACID라는 특징이 있다.
•
원자성(Atomicity)
트랜잭션이 데이터베이스에 완전히 반영되거나 아예 실행되지 않아야 한다.
•
일관성(Consistency)
트랜잭션 수행이 완료된 데이터베이스는 일관성이 있다.
•
독립성(Isolation)
수행 중인 트랜잭션에 다른 트랜잭션이 끼어들 수 없다.
•
영속성(Durability)
완료한 트랜잭션의 결과가 데이터베이스에 영구적으로 반영된다.
원자성 때문에 트랜잭션은 완전히 반영되거나 아예 실행되지 않아야 한다.
그래서 트랜잭션을 제어하기 위해 TCL(Transaction Control Language)이라는 명령어를 사용한다.
TCL의 종류는 다음과 같다.
•
COMMIT
트랜잭션이 정상적으로 종료되어 데이터베이스에 변경 사항을 반영하는 명령어다.
•
ROLLBACK
트랜잭션이 비정상적으로 종료되어 트랜잭션이 수행한 변경 사항을 취소하고 데이터베이스를 이전 상태로 되돌리는 명령어다.
•
SAVEPOINT
트랜잭션에서 특정 지점을 지정하는 명령어로 ROLLBACK과 함께 사용하면 해당 지점까지 되돌릴 수 있다.
여러 트랜잭션이 서로 영향을 미치지 않고 실행될 수 있는 단계를 트랜잭션 격리 수준(transaction isolation level)이라고 한다.
이는 한 트랜잭션이 다른 트랜잭션 작업의 조회 가능 여부를 결정한다.
트랜잭션 격리 수준은 다음과 같이 4단계로 나눈다.
•
Read Uncommited
트랜잭션의 COMMIT 여부와 상관없이 다른 트랜잭션이 데이터를 조회할 수 있다.
한 번에 여러 트랜잭션을 처리할 수 있는 동시성은 높지만 데이터의 일관성을 유지하기 어렵다.
•
Read Commited
트랜잭션이 COMMIT된 데이터만 다른 트랜잭션이 조회할 수 있다.
•
Repeatable Read
트랜잭션이 읽은 데이터를 다른 트랜잭션이 갱신하거나 삭제할 수 없다.
•
Serializable
트랜잭션이 읽은 데이터를 다른 트랜잭션이 갱신, 삭제, 삽입할 수 없다.
동시성이 높아지면 여러 트랜잭션이 동시에 처리되고 데이터의 일관성에 문제가 발생할 확률도 높아진다.
반면, 고립성을 높이면 하나의 트랜잭션이 처리 중일 때 다른 트랜잭션의 접근이 제한되어 효율이 낮아진다.
그러므로 상황에 따라 데이터의 일관성을 유지하면서 트랜잭션을 효율적으로 처리할 수 있어야 한다.
락
락(lock)은 트랜잭션이 처리되는 순서를 보장하기 위한 방법이다.
운영체제에서 데이터 동기화를 위해 임계 영역에 대한 접근을 제한하는 상호배제 기법과 유사하다.
데이터의 무결성을 유지하기 위한 락이 여러 종류가 있는데 대표적인 락은 다음과 같다.
•
공유 락(shared lock)
데이터를 읽는 락으로 읽기 락(read lock)이라고도 한다.
데이터를 읽는 연산이므로 데이터의 일관성에 영향을 주지 않아 데이터에 여러 공유 락이 동시에 접근할 수 있다.
•
베타 락(exclusive lock)
데이터를 수정하는 락으로 쓰기 락(write lock)이라고도 한다.
데이터의 일관성을 유지하기 위해 데이터에 하나의 베타 락이 접근 중일 때 다른 베타 락이 접근할 수 없다.
데이터베이스의 트랜잭션도 프로세스처럼 교착 상태(deadlock)에 빠질 수 있다.
이는 한 트랜잭션이 자신이 처리 중인 데이터에 대해 락을 가진 상태에서 다른 트랜잭션이 처리 중인 데이터에 대해 락을 요청해 무한 대기 상태에 빠진 현상을 의미한다.
즉, 특정 데이터의 락을 가지고 있는 트랜잭션이 다른 데이터의 락을 추가로 요청하며 발생한다.
트랜잭션의 교착 상태를 해결하기 위한 방법은 다음과 같다.
예방 기법
트랜잭션 처리가 시작되기 전에 필요한 데이터에 대해 미리 락을 얻는 방식이다.
회피 기법
트랜잭션이 들어온 순서에 따라 교착 상태를 회피하는 방식이다.
•
wait-die
데이터의 락을 요청하려는 트랜잭션이 해당 데이터에 대해 이미 락을 갖고 있는 트랜잭션보다 오래되었다면 락을 얻을 때까지 기다린다.
반면, 락을 갖고 있는 트랜잭션보다 최신이라면 락 획득을 포기한다.
•
wound-wait
데이터의 락을 요청하려는 트랜잭션이 해당 데이터에 대해 이미 락을 갖고 있는 트랜잭션보다 오래되었다면 락을 빼앗는다.
반면, 락을 갖고 있는 트랜잭션보다 최신이라면 락 획득을 기다린다.
이상
이상(anomaly)은 트랜잭션을 처리하는 중에 속성 간 종속이나 데이터 중복으로 발생하는 문제를 일컫는다.
•
삽입 이상(insertion anomaly)
데이터 삽입 시 의도치 않은 다른 데이터도 삽입된다.
•
갱신 이상(update anomaly)
데이터 갱신 시 일부 튜플만 갱신되어 데이터 모순이 발생한다.
•
삭제 이상(deletion anomaly)
데이터 삭제 시 의도하지 않은 데이터도 삭제된다.
정규화
정규화(normalization)는 데이터베이스의 이상 현상을 해결하기 위해 테이블을 분해하는 것이다.
하지만 테이블을 분해하느라 연산 시간이 증가한다는 단점이 있다.
따라서 테이블을 무조건 분해하는 것이 아니라 상황에 따라 적절하게 정규화를 진행해야 한다.
그래야 이상 현상을 해결하고 연산 속도를 보장할 수 있다.
정규화한 결과를 정규형(normal form)이라고 하며 테이블을 분해하는 정도에 따라서 단계를 다음과 같이 나눌 수 있다.
제1정규형
제1정규형(First Normal Form)은 테이블의 모든 속성 값이 더 이상 분해될 수 없는 값, 즉 원자 값으로 구성되어야 한다.
제2정규형
제2정규형(Second Normal Form)은 제1정규형에 속하는 테이블에서 부분적 함수 종속을 제거해 완전 함수 종속을 만족해야 한다.
함수 종속성은 테이블에서 속성 간 종속 관계를 의미한다.
예를 들어, A 속성이 B 속성을 결정하면 B 속성이 A 속성에 함수 종속된다고 하고 A를 결정자, B를 종속자라고 한다.
완전 함수 종속은 A 속성이 B 속성을 결정하지만 A 속성의 진부분집합이 B 속성을 결정하지 않는 경우를 의미한다.
따라서 부분적 함수 종속은 기본 키의 부분집합이 결정자가 될 수 있음을 의미한다.
즉, 기본 키의 진부분집합이 결정자가 될 수 없도록 테이블을 분해해야 완전 함수 종속을 만족한다.
제3정규형
제3정규형(Third Normal Form)은 제2정규형에 속하는 테이블에서 이행적 종속이 없어야 한다.
이행적 종속은 A 속성이 B 속성을 결정하고 B 속성이 C 속성을 결정할 때 A 속성이 C 속성을 결정하는 것을 의미한다.
이런 경우 A 속성이 C 속성을 결정하는 이행적 종속을 제거해야 한다.
즉, A 속성이 B 속성을 결정하는 테이블과 B 속성이 C 속성을 결정하는 테이블로 분해해야 한다.
보이스-코드 정규형
보이스-코드 정규형(Boyce-Codd Normal Form)은 강한 제3정규형이라고도 한다.
제3정규형에 속하는 테이블이 모든 결정자가 후보 키가 되도록 테이블을 분해해야 한다.
제4정규형
제4정규형(Fourth Normal Form)은 제3정규형에 속하면서 다치 종속을 제거해야 한다.
다치 종속은 테이블에서 한 속성이 여러 속성의 값을 결정하는 것을 의미한다.
제5정규형
제5정규형(Project Join Normal Form)은 제4정규형에 속하면서 조인 종속이 없어야 한다.
조인 종속이 없다는 것은 테이블을 분해했다가 조인할 때 테이블이 복원된다는 것을 의미한다.
역정규화(denormalization)
역정규화는 정규화된 테이블을 낮은 정규화 단계의 테이블로 되돌리는 것으로 읽기 성능을 향상시킬 때 사용한다.
정규화를 수행하면 테이블이 분해되므로 필요한 결과 데이터를 얻기 위해 조인 연산을 여러 번 수행해야 한다.
이 때문에 데이터베이스를 빈번히 조회하는 경우 성능 저하가 생길 수 있다.
그래서 오히려 중복을 허용하는 역정규화를 수행한다.