July
26th,
2021
- InnoDB는 MySQL에서 사용할 수 있는 스토리지 엔진 중, 유일하게 레코드 기반 잠금을 제공하고, 그로 인해 동시성 처리가 가능하며 안정적이다. *
3.2.1 InnoDB 스토리지 엔진의 특성
- 프라이머리 키에 의한 클러스트링
- InnoDB의 모든 테이블은 기본적으로 프라이머리 키 기준으로 클러스터링 되어 저장된다(PK 값 기준으로 디스크에 저장된다)
- 오라클 DBMS의 IOT와 동일한 구조다.
- 잠금이 필요 없는 일괄된 읽기
- InnoDB 스토리지 엔진은 MVCC(Multi Version Concurrency Control)라는 기술을 이용해 락을 걸지않고 읽기 작업을 수행한다.
- 외래 키 지원
- MyISAM, MEMORY 테이블에서는 지원하지 않는 외래 키를 지원한다.
- 자동 데드락 감지 * 그래프 기반 데드락 체크 방식을 사용하기 때문에, 데드락이 발생함과 동시에 바로 감지된다. * 감지된 데드락은 관련 트랜잭션 중 ROLLBACK이 가장 용이한 트랜잭션을 자동적으로 강제종료한다.
- 자동화된 장애 복구
- MySQL 서버가 시작될 때, 완료되지 못한 트랜잭션이나 디스크에 일부만 기록된 페이지(Partial write)등에 대한 일련의 복구 작업이 자동으로 진행된다.
- 오라클 아키텍처 적용
- MVCC 기능 제공, 언두(Undo) 데이터 관리, 테이블 스페이스 개념등이 오라클 DBMS와 비슷하다
3.2.2 InnoDB 버퍼 풀
- InnoDB 스토리지 엔진에서 가장 핵심적인 부분이라고 할 수 있다.
- 디스크의 데이터 파일이나 인덱스 정보를 메모리에 캐시해두는 공간이다. 쓰기 작업을 지연시켜 일괄적으로 처리해줄 수 있는 역할도 한다.
- MyISAM 키 캐시가 인덱스의 캐시만을 처리하는데에 반해, InnoDB의 버퍼 풀은 데이터와 인덱스 모두 캐시하고 쓰기 버퍼링의 역할까지 처리한다.
- 일반적으로 InnoDB의 버퍼 풀은 물리 메모리의 50~80% 수준 내로 셋팅한다.
3.2.3 언두(Undo) 로그
- 언두 영역은 UPDATE, DELETE와 같이 데이터 변경시 변경 전 데이터를 보관하는 공간이다.
UPDATE member SET name = '홍길동' WHERE member_id = 1;
- 위와 같이 sql 쿼리 실행시, 커밋하지 않아도 실제 데이터 파일(데이터/인덱스 버퍼) 내용은 “홍길동”으로 변경된다.
- 언두 영역에는 변경전 데이터가 백업되는 개념이다.
- 커밋시에는 현재 상황을 유지하고, 롤백시에 언두 영역의 데이터를 다시 데이터 파일로 복구한다.
언두는 크게 두 가지 용도로 사용된다 :
- 트랜잭션 롤백 대비
- 트랜잭션 격리 수준을 유지하며 높은 동시성을 제공하기 위해 사용
3.2.4 인서트 버퍼(Insert Buffer)
- RDBMS에서 레코드가 INSERT되거나 UPDATE될 때 데이터 파일을 변경하는 작업 뿐 아니라, 해당 테이블에 포함된 인덱스를 업데이트 하는 작업도 필요하다.
- 인덱스 업데이트시, 디스크를 랜덤하게 읽는 작업이 필요해 인덱스가 많으면 많은 자원을 소모한다.
- InnoDB는 변경해야 할 인덱스 페이지가 버퍼 풀에 있으면 바로 업데이트를 수행하고, 그렇지 않고 디스크로부터 읽어와서 업데이트를 해야 할 경우 즉시 실행하지 않고 임시 공간에 저장해두고 바로 사용자에게 결과를 반환하는 형태를 띈다.
- 유니크 인덱스는 인서트 버퍼를 사용할 수 없다.(사용자에게 결과 전달하기 전 중복 여부를 반드시 체크해야 하므로)
3.2.5 리두(Redo) 로그 및 로그 버퍼
- 쿼리로 데이터 변경 후, 커밋하면 DBMS는 ACID를 보장하기 위해 즉시 변경된 데이터의 내용을 데이터 파일로 기록해야 한다.
- 이 때, 데이터 파일의 변경 작업은 랜럼하게 디스크에 기록되기 때문에 부하를 줄이기 위해 변경된 데이터를 버퍼링해두는 버퍼 풀이 있다.
- 위 버퍼 풀만으로는 ACID를 보장할 수 없어, 변경된 내요을 순차적으로 디스크에 기록하는 로그 파일을 갖고 있는데, 이 파일을 리두 로그라고 한다.
- 리두 로그 덕분에 DBMS 데이터는 버퍼링을 통해 한꺼번에 디스크에 변경된 내용을 처리할 수 있고, 그로 인해 성능 향상을 기대할 수 있다.
- 리두 로그 버퍼링에 사용되는 공간은 로그 버퍼라고 하며, 일반적으로 1~8MB로 설정하는 것이 적합하다.
3.2.6 MVCC(Multi Version Concurrency Control)
- 일반적으로 레코드 레벨의 트랜잭션을 지원하는 DBMS가 제공하는 기능이다.
- 잠금을 사용하지 않는 일괄된 읽기를 위해 주로 사용한다.
- 멀티버전 ? 하나의 레코드에 여러 개의 버전이 동시에 관리된다는 의미
- 주로 DBMS 격리수준과 관련이 되어있다고 볼 수 있다(READ COMMITED일 때를 가정해, 커밋 전에는 다른 쓰레드에서는 업데이트 전 데이터를 보여주고, 커밋했을 경우에만 바뀐 데이터로 부여주어야 함)
3.2.7 잠금없는 일관된 읽기(Non-locking consistent read)
- InnoDB에서 격리수준이 SERIALIZABLE이 아닐 경우(READ-UNCOMMITED, READ-COMMITED, REPEATABLE-READ), INSERT와 연결되지 않은 순수 읽기(SELECT)작업은 다른 트랜잭션의 변경 작업과 관계 없이 항상 잠금을 대기하지 않고 바로 실행된다.
- 변경 전 데이터를 읽기 위해서 언두로그를 사용한다.
3.2.8 InnoDB와 MyISAM 스토리지 엔진 비교
- MySQL 5.5부터 InnoDB 스토리지 엔진이 기본 스토리지 엔진으로 채택되었다.
- 아래의 컬럼을 읽었을때 각각 스토리지 엔진 별 성능차이를 확인해보자.
- 프라이머리 키(데이터 파일 읽기 포함) : InnoDB가 6-9% 빠름
- 보조 인덱스(데이터 파일 읽기 포함) : 64개 이하의 동시 스레드에서는 비슷함, 그 이후는 InnoDB가 400-500% 빠름
- 보조 인덱스(데이터 파일 읽기 포함 + LIMIT ) : 256개 이하의 동시 스레드 이하에서는 InnoDB가 25~50%빠르나, 그 이상은 비슷함
- 보조 인덱스(커버링 인덱스) : InnoDB가 30% 정도 빠름
- 보조 인덱스 (커버링 인덱스 + LIMIT 사용) : 256개 스레드 이하에서는 InnoDB가 80% 빠르고 그 이상은 비슷함
- PK(커버링 인덱스) : 성능차이 없음
- PK Range Scan(일부) : InnoDB가 200~2600% 빠름
- PK Range Scan(전체) : 256개 스레드 이하에서는 InnoDB가 30% 빠르고 그 이상에서는 MyISAM이 5%정도 빠름
- 보조 인덱스 Range Scan(데이터 파일 읽기 포함) : 스레드 128개 이하에선 성능차이 없고, 그 이상에서 InnoDB가 600%가량 빠름
- 보조 인덱스 Range Scan(데이터 파일 읽기 포함 + LIMIT 사용 ) : InnoDB가 평균 10% 빠름
- 보조 인덱스 Range Scan(커버링 인덱스) : InnoDB가 2~30% 빠름
- 보조 인덱스 Range Scan(커버링 인덱스 + LIMIT) : InnoDB가 2~30% 빠름
- 풀 테이블 스캔 : InnoDB가 20% 빠름
정리해서 봤을 때, 엄청나게 많은 스레드가 PK Range Scan을 전체 진행했을 경우에만 MyISAM이 빠르고, 그 경우에는 InnoDB에서 조회하는 것이 더 빠른 것을 확인할 수 있다.
InnoDB가 MyISAM보다 서버 설정 튜닝이 더 복잡하지만, 위 성능을 비교해봤을 때는 튜닝을 고려해보는 것이 더 적절해보인다.
3.2.9 InnoDB와 MEMORY(HEAP) 스토리지 엔진 비교
- MEMORY 스토리지 엔진은 데이터와 인덱스를 모두 메모리에 저장해 저장작업, 읽기 작업이 매우 빠르다.
- 하지만 MEMORY 스토리지는 테이블 수준의 잠금을 이용하기 때문에 동시에 두 개 이상의 클라이언트가 테이블을 변경할 수 없다.
- 테이블 수준의 잠금을 사용하는 MEMORY 스토리지 엔진보다, 레코드 수준의 잠금을 사용하는 InnoDB 스토리지 엔진이 훨씬 빠른 트랜잭션 처리를 보장해준다.
- MEMORY 테이블은 여러 커낵션에 의해 읽기 위주로 사용되는 경우, 또는 단일 커넥션으로 사용될 때는 적합하지만 동시에 많은 커넥션이 트랜잭션을 유발하는 OLTP 환경에서는 적합하지 않다.