이번 포스트에서는 MySQL의 스토리지 엔진 중 하나인 InnoDB 스토리지 엔진 아키텍처에 대해서 포스트하려합니다.
InnoDB는 MySQL에서 사용할 수 있는 스토리지 엔진 중 거의 유일하게 레코드 기반의 잠근을 제공합니다(InnoDB 스토리지 엔진 잠금은 5.3에서 자세히 다룰 예정). 이로 인해 높은 동시성 처리가 가능하고 안정적이며 성능이 뛰어납니다.
프라이머리 키에 의한 클러스터링
InnoDB의 테이블은 기본적으로 프라이머리 키를 기준으로 클러스터링이되어 저장됩니다. 즉 프라이머리 키 값의 순서대로 디스크에 저장된다는 뜻이며, 모든 세컨더리 인덱스는 레코드의 주소 대신 프라이머리 키의 값을 논리적인 주소로 사용합니다. 쿼리 실행 계획에서 프라이머리 키는 다른 보조 인덱스에 비해 비중이 높게 설정되고 프라이머리 키를 이용한 레인지 스캔은 상당히 빨리 처리될 수 있습니다.
외래 키 지원
외래 키에 대한 지원은 InnoDB 스토리지 엔진 레벨에서 지원하는 기능으로 MyISAM, MEMORY 테이블에서 는 사용할 수 없습니다.
외래 키는 부모 테이블(PK)과 자식 테이블(FK) 모두 해당 칼럼에 인덱스 생성이 필요하고, 변경 시에는 반드시 부모 테이블이나 자식 테이블에 데이터가 있는지 체크하는 작업이 필요하므로 잠금이 여러 테이블로 전파되고, 그로 인해 데드락이 발생할 때가 많으므로 외래 키 존재에 대해 주의하는 것이 좋습니다.
외래 키가 적용되어 있는 테이블의 경우 데이터를 적재하거나 스키마 변경 등의 관리 작업이 실패할 수 있습니다. 부모와 자식 테이블 관계를 명확히 파악해서 순서대로 작업을 진행한다면 문제없이 실행될 수 있지만 외래 키 관계가 복잡해질 경우 간단하게 해결이 안 되는 경우가 더 많습니다. 이러한 문제점을 해결하기 위해 foreign_key_checks 시스템 변수를 OFF로 설정하면 외래 키 관계에 대한 체크 작업을 하지 않게되며 데드락에 대한 문제점이나 테이블의 데이터를 적재하거나 삭제하는 등의 작업을 수월하게 할 수 있습니다. 하지만 외래 키 체크를 일시적으로 해제했다 해서 부모와 자식 테이블 간의 외래 키 관계가 깨진 상태로 유지가 되면 안되기 때문에 반드시 테이블 간에 일관성을 맞춰주고 외래 키 체크 기능을 다시 활성화로 돌려 놓아야 합니다.
MVCC(Multi Version Concurrency Control)
레코드 레벨의 트랜잭션을 지원하는 DBMS가 제공하는 기능이며, 잠금을 사용하지 않는 일관된 읽기를 제공합니다. InnoDB는 언두 로그(Undo log)를 이용해 이 기능을 구현합니다. 멀티 버전은 하나의 레코드에 대해 여러 개의 버전(언두 로그에서)이 동시에 관리된다는 의미입니다.
update 문장이 실행되면 커밋 실행 여부와 관계 없이 InnoDB의 버퍼 풀은 새로운 값이 적용됩니다. 그리고 디스크의 데이터 파일에는 체크포인트나 InnoDB Write 스레드에 의해 새로운 값으로 업데이트가 되어 있을 수도 아닐 수도 있습니다.(InnoDB는 ACID를 보장하기 때문에 버퍼 풀과 디스크의 데이터 파일은 동일한 상태라고 가정해도 무방)
격리 수준이 READ_UNCOMMITED인 경우에는 InnoDB 버퍼 풀이 현재 가지고 있는 변경된 데이터를 반환합니다.
그렇지 않고 그 이상의 격리 수준인 READ_COMMITED, REPEATABLE_READ, SERIALIZABLE인 경우에는 아직 커밋이 되지 않았기 때문에 버퍼 풀이나 디스크 데이터 파일에 있는 데이터 대신 변경되기 이전의 내용을 보관하고 있는 언두 영역의 데이터를 반환합니다.
이러한 과정을 DBMS에서는 MVCC라고 표현합니다. 즉 하나의 레코드에 대해 여러개의 버전이 유지되고, 필요에 따라 어느 데이터가 보여지는지 달라진 구조입니다.
COMMIT 명령어를 실행하면 버퍼 풀의 데이터를 영구적인 데이터로 만들고 ROLLBACK을 실행하면 언두 영역에 백업된 데이터를 버퍼 풀로 다시 복구하고 언두 영역의 데이터는 삭제합니다.
또 한 InnoDB는 MVCC 기술을 이용해 잠금을 걸지 않고 읽기 작업을 수행합니다.
격리 수준이 SERIALIZABLE이 아닌 READ_UNCOMMITED, READ_COMMITED, REPEATABLE_READ인 경우 INSERT와 연결되지 않은 순수한 읽기(SELECT) 작업은 다른 트랜잭션의 변경 작업과 관계 없이 항상 잠금을 대기하지 않고 바로 실행됩니다.
특정 사용자가 레코드를 변경하고 아직 COMMIT을 수행하지 않았다 하더라도 이 변경 트랜잭션이 다른 사용자의 SELECT 작업을 방해하지 않습니다. 이 부분을 잠금 없는 일관된 읽기(Non-Locking Consistent Read)라고 표현하며, InnoDB에서는 변경되기 전의 데이터를 읽기 위해 언두 로그를 사용합니다.
'ComputerScience > RealMySQL' 카테고리의 다른 글
5.트랜잭션과 잠금 - InnoDB 스토리지 엔진 잠금 (0) | 2022.12.11 |
---|---|
5.트랜잭션과 잠금 - 트랜잭션과 MySQL 엔진의 잠금 (0) | 2022.12.05 |
4.MySQL 아키텍처 - 4.2 InnoDB 스토리지 엔진 아키텍처(2) (0) | 2022.12.01 |
4.MySQL 아키텍처 - 4.1 MySQL 엔진 아키텍처(2) (0) | 2022.11.28 |
4.MySQL 아키텍처 - 4.1 MySQL 엔진 아키텍처(1) (0) | 2022.11.22 |