[MySQL] innoDB

InnoDB

InnoDB 스토리지 엔진 특성

프라이머리 키에 의한 클러스터링

InnoDB는 기본적으로 프라이머리키를 기준으로 클러스터링 되어 저장된다. 그렇기 때문에 프라이머리 키에 의한 레인지 스캔은 빠르게 커리될 수 있으며 쿼리 실행 계획에서 프라이머리 키는 다른 보조 인덱스에 비해 비중이 높게 설정된다. 즉, 프라이머리 키를 선택해 쿼리를 실행할 확률이 높아진다.

Non-locking consistent read

InnoDB에서 순수한 읽기 작업은 MVCC(Multi Version Concurrency Control)을 통해 락을 걸지 않고 읽기 작업을 수행한다. 락을 걸지 않기 때문에 다른 트랜잭션이 가지고 있는 락을 기다리지도 않는다. 단, SERIALIZABLE 격리 수준 제외한다.

외래키 지원

외래키는 InnoDB 스토리지 엔진 레벨에서 지원을 한다. 하지만 외래키를 잘못 사용하게 되면 데드락의 위험이 있다. 가령 외래키는 부모 테이블과 자식 테이블 모두 해당 칼럼에 인덱스 생성이 필요하고, 변경시에는 부모와 자식 테이블 모두 해당 데이터가 있는지 확인하는 작업이 필요하므로 잠금이 여러 테이블에 전파되어 데드락이 발생하게 된다.

자동 데드락 감지

InnoDB는 그래프 기반의 데드락 체크 방식을 사용하여 데드락을 감지한다. 감지된 데드락은 관련 트랜잭션중 ROLLBACK이 가장 용이한 트랜잭션을 선택해 종료시킨다.

InnoDB 버퍼 풀

INSERT, UPDATE, DELETE같이 데이터를 변경시키는 쿼리는 데이터 파일의 다양한 영역에 접근해 레코드를 변경하기 때문에 랜덤 디스크 IO를 유발시킨다. InnoDB는 버퍼풀을 사용하여 변경된 데이터를 모아 한꺼번에 처리할 수 있다. 그 외에도 버퍼 풀에는 인덱스를 캐시해둘 수 있는데 인덱스의 크기가 크다면 그만큼 캐시해둘 수 있는 레코드의 크기가 줄어든다. 그렇기 때문에 적절한 인덱스 컬럼의 선택도 중요하다.

Undo 로그

Undo 로그는 UPDATE, DELETE로 데이터를 변경했을 때 변경되기 전의 데이터를 보관하는 영역이다. 이 영역은 트랜잭션의 롤백 대비용이나 트랜잭션 격리 수준을 유지하면서 높은 동시성을 제공하는데 사용된다.

Insert Buffer

레코드가 INSERT나 UPDATE될 때는 테이블에 포함된 인덱스를 업데이트하는 작업이 필요하다. 이 작업 또한 랜덤 디스크 IO를 유발하므로 이를 방지하기 위해 사용한다. InnoDB 버퍼 풀에 변경해야할 인덱스 페이지가 있다면 바로 변경하지만, 디스크에서 읽어와 변경해야 한다면 Insert Buffer에 저장해두고 사용자에게는 결과를 반환한다.

Redo 로그

쿼리를 수행하고 커밋을 진행하면 ACID를 보장하기 위해 데이터를 파일로 기록해야 하는데, 이런 작업은 랜덤 디스크 IO를 유발하게 된다. 이 부하를 줄이기 위해 버퍼 풀과 같은 장치를 마련했으나 ACID를 완벽히 보장할 수는 없다. 그렇기에 변경된 내용을 순차적으로 기록하는 로그 파일을 지니고 있으며 이 로그 파일이 Redo 로그이다.

MVCC - Multi Version Concurrency Control

MVCC의 가장 큰 목적은 잠금을 사용하지 않는 일관된 읽기 방법을 제공하는 것이다. UPDATE 쿼리를 수행하고 커밋하지 않은 상태에서 해당 레코드를 조회한다고 예를 든다면 반환되는 데이터는 격리 수준에 따라 달라진다.

READ_UNCOMMITED라면 버퍼 풀에서 데이터를 읽어오게 된다. 하지만 그 이상의 격리 수준이라면 언두 영역에 데이터를 반환하게 되는데, 하나의 레코드에 대한 다양한 버전을 관리하기 때문에 MVCC다.

Author: Song Hayoung
Link: https://songhayoung.github.io/2020/09/02/Database/innoDB/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.