우선 Undo영역에 대한 이해부터 하고 넘어가자.
MVCC(Multiversion Concurrency Control) 란?
잠금 없이 일관된 읽기를 제공하는 것으로, 크게 두 가지 접근법이 있다.
1. Perssimistic Lock : DB에 다중 버전의 레코드를 저장해 두고, 더 이상 필요하지 않을 때 모아둔 레코드를 버리는 방식
- PostgreSQL, SQL server 등에서 사용
2. Undo : 최신 버전의 데이터만 DB 안에 저장해 두고, Undo를 이용하여 이전 버전의 데이터를 재구성하는 방식
- MySQL InnoDB, Oracle 등에서 사용
어떤 레코드에 대해 UPDATE 쿼리 등의 write가 발생하면 Undo에는 이전 이미지를 넣고, 버퍼 풀에는 새로 write한 내용을 가지고 있어 두 개의 상태를 가지게 된다. 이 상태에서 SELECT로 레코드를 조회하면 격리 수준에 따라 값이 다르게 나오는 것이 MVCC이다.
저번 글에서는 InnoDB의 트랜잭션에 대해 다뤄보았다.
그렇다면 InnoDB에서는 트랜잭션 처리에 따른 Redo 로그와 Undo 정보, 동시에 MVCC의 구현을 어떤 flow를 통해서 하는지 복습해보자.
1. 트랜잭션 시작
begin;
2. 레코드의 특정 컬럼의 값을 변경하는 쿼리가 실행됨 (UPDATE)
UPDATE user SET area='경기' WHERE userid='brew';
2-1. 변경되는 컬럼의 이전 값을 저장하는 Undo 로그 레코드가 생성됨 (단, Undo로그에는 이전 값과 PK값만 저장됨)
Address | Old-Tx-id | Old-Roll-pointer | PK(Primary Key) | Undo-Data |
xx | yyy | brew | AREA: 서울 |
2-2. 버퍼 풀 데이터 페이지에서 변경 대상 레코드의 정보 중 roll-pointer의 값을 2-1에서 생성된 Undo로그의 주소값으로 저장함
Address | Old-Tx-id | Old-Roll-pointer | PK(Primary Key) | Undo-Data |
<PTR-3> | xx | yyy | brew | AREA: 서울 |
2-3. 버퍼 풀 데이터 페이지의 변경 대상 레코드의 컬럼 값을 UPDATE하고(서울->경기), 변경된 칼럼의 이후 값 + 데이터 페이지의 주소와 Offset을 Redo로그에 저장함
LSN | Page # | Offset | Log Type | Redo-Data |
1 | 1541 | 121 | UPDATE | AREA: 경기 |
2-4. 변경되는 칼럼을 이용한 인덱스가 존재하는 경우(예시에서는 area칼럼에 인덱스가 있음), 인덱스 값을 변경함. 인덱스 값은 기존의 값은 보존하면서 새로운 키값을 추가하는 식으로 관리! 해당 인덱스가 버퍼 풀에 없으면 인서트 버퍼에 임시로 저장함.
즉, 인덱스 키는 트랜잭션과 상관 없이 모든 값들을 다 가지고 있게 된다.
2-5. Redo 로그는 디스크의 로그 파일로 기록된다. 단, Redo로그의 dirty page(변경된 페이지)가 기록되기 전에, 이 page를 만든 LSN(Log Sequence #)보다 이전의 LSN Redo Log가 존재한다면 반드시 이전 것 먼저 수행되고 순서대로 기록되어야 함!!
3. 체크포인트 발생
- 체크포인트로 디스크에 기록되는 데이터가 모두 commit된 데이터는 아닐 수 있음!!
- 왜냐하면, 모든 데이터를 다 메모리에 들고 있기는 불가능하므로 Undo의 메모리 영역 이외에도 disk 내에 dirty page를 변경시킨 LSN과 연관된 Undo로그를 파일로도 관리함
- 즉, 체크포인트가 발생하면 Undo 메모리에 있는 데이터도 물리적인 디스크에 저장해야 한다.
- Undo 로그가 디스크에 기록되어 있지 않으면 현재 디스크로 저장되는 페이지를 ROLLBACK할 수 없게 되기 때문
- 결론 : 꼭 commit되지 않아도, Undo에 관한 내용은 디스크에 남아있으므로 언제든지 ROLLBACK할 수 있다.
휴 길다
"InnoDB에서 UPDATE 쿼리가 들어왔을 때 실제 물리적인 disk까지 쓰여지는 동작"을 한마디로 정리하면
- UPDATE 쿼리가 실행되면 이전 값은 Undo로그에, 새로운 값은 버퍼 풀에 저장됨
- 여기서 변경되는 컬럼을 이용한 인덱스가 있으면 인덱스의 값도 변경(기존 인덱스 키에 새로운 키값 추가), 해당 인덱스 페이지가 버퍼 풀에 없으면 insert 버퍼에 저장
- 그리고 언제든지 ROLLBACK할 수 있게 InnoDB의 dirty page를 변경시킨 Undo 로그를 디스크에 저장
- 체크포인트가 발생하면 변경된 인덱스 페이지 + 디스크 페이지를 디스크에 기록
InnoDB에서 어떤 식으로 Undo를 이용해서 MVCC가 구현되는지 그 과정을 이해하고 잘 알아두자.
본 글은 <Real MySQL>의 저자이신 이성욱 님의 블로그를 참고하였습니다!
'MySQL' 카테고리의 다른 글
[InnoDB] In-memory buffer의 종류 (0) | 2021.02.19 |
---|---|
06. 트랜잭션에 대한 격리 수준(isolation level) (0) | 2020.06.23 |
04. MySQL에서의 잠금 - (2) MyISAM과 MEMORY 스토리지 엔진 (0) | 2020.06.15 |
04. MySQL에서의 잠금 - (1) MySQL 엔진 (0) | 2020.06.15 |
03. 트랜잭션 (0) | 2020.06.15 |