Database/High Performance MySQL

MySQL 아키텍처

Seung-o 2023. 7. 23. 20:23

MySQL의 논리적 아키텍처

 

MySQL의 논리적인 뷰는 아래와 같은 그림과 같이 크게 세 개의 계층으로 나타낼 수 있다. 최상위 계층인 클라이언트부터 최하위 계층인 스토리지 엔진까지는 다음과 같이 역할이 분담되어 있다.

 

- 첫 번째 계층 ( 클라이언트 ):  네트워크 기반 클라이언트 / 서버 도구 또는 서버에 필요한 연결 처리, 인증, 보안.

- 두 번째 계층 ( 파서, 옵티마이저 등 ): 쿼리 파싱, 분석, 최적화 및 모든 기본 제공 함수 등 MySQL의 대부분의 지능적인 부분.

- 세 번째 계층 ( 스토리지 엔진 ): MySQL에 데이터를 저장하고 검색하는 역할. 서버는 스토리지 엔진 API를 통해 통신하고, 이 API는 스토리지 엔진 간의 차이를 숨겨서 쿼리 계층에서는 그 차이를 느끼지 못함. "트랜잭션 시작 " 또는 "특정 기본키를 지닌 행 가져오기"와 같은 작업을 수행하는 수십 개의 하위 수준 함수도 포함하고 있음. 스토리지 엔진은 SQL 구문 분석을 하거나 서로 통신을 하지 않으며, 단순히 서버의 요청에 응답할 뿐임.

 

MySQL의 논리적인 뷰

연결 관리 및 보안

 

각 클라이언트 연결은 서버 프로세스 내에서 고유한 스레드를 가진다. 연결 쿼리는 하나의 코어 또는 CPU에 존재하는 단일 스레드 내에서 실행된다. 서버는 즉시 사용할 수 있는 스레드의 캐시를 유지 관리하므로, 새로운 연결마다 매번 스레드를 생성하거나 폐기할 필요는 없다. 

 

클라이언트가 MySQL 서버에 연결되면 서버에서 인증을 해야한다. 인증은 사용자 이름, 호스트, 암호에 기반한다. 클라이언트가 연결되면 서버는 클라이언트에서 보내는 각 쿼리에 대한 권한이 있는지 확인한다. 

 

최적화 및 실행

 

MySQL은 쿼리를 구문 분석하여 "분석 트리"를 생성한 다음, 다양한 최적화를 적용한다. 여기서 최적화란, 쿼리 재작성 / 테이블을 읽는 순서 결정 / 사용할 인덱스 선택 등이 포함된다. 이 때, 쿼리의 특수 키워드를 통해 옵티마이저에 힌트를 전달하여 의사 결정 프로세스에 영향을 줄 수 있다. ( USE INDEX 와 같은 구문을 의미하는 듯 하다 ) 또한, 서버에게 최적화의다양한 측면을 설명하게 요청할 수도 있다. ( EXPLAIN 구문을 의미하는 듯 하다 ) 

 

옵티마이저는 특정 테이블이 어떤 스토리지 엔진을 사용하는지에는 관심이 없지만, 스토리지 엔진은 서버가 쿼리를 최적화 하는 방법에 영향을 미친다. 그래서 옵티마이저는 최적화를 위해 스토리지 엔진에게 테이블 데이터에 대한 통계 뿐만 아니라 일부 기능과 특정 작업 비용에 대해 묻는다. ( 이 부분은 추후 6장과 7장 리뷰에서 자세히 다룬다 )

 

MySQL 5.7.20 버전 이전에는 MySQL이 내부 쿼리 캐시를 사용하여 결과를 처리했지만, 동시성이 증가함에 따라 쿼리 캐시는 악명 높은 병목 구간이 되어 버렸다. 그래서 이후 버전부터는 쿼리 캐시는 MySQL 기능으로 더 이상 사용되지 않으며, 8.0 버전부터는 완전히 사라졌다. 하지만 자주 제공되는 결과 셋은 캐싱하는 것이 유리하므로, memcached 또는 Redis 캐시 디자인 패턴을 활용하기를 추천한다. 

 

동시성 제어

 

두 개 이상의 쿼리가 동시에 같은 데이터를 변경해야할 때, 동시성 제어 문제가 발생한다. MySQL은 서버와 스토리지 엔진의 두 레벨에서 이 동시성 작업을 수행한다. 다음은 동시성 작업 ( 읽기 / 쓰기 )을 MySQL이 어떻게 처리하는지에 대한 개요이다.

 

읽기/쓰기 잠금

 

동시성 제어에 대한 가장 간단한 해결책은 "잠금"이다. 즉, 읽기와 쓰기 작업가 수행되는 시점에 "잠금"을 걸고, 동일한 리소스에 많은 클라이언트의 접근을 제어하는 것이다. 
읽기에 대한 잠금을 공유 잠금 ( Shared Lock ) / 쓰기에 대한 잠금을 전용 잠금 ( Exclusive Lock ) 이라고 한다. 공유 잠금에서는 많은 클라이언트가 리소스를 동시에 읽을 수 있으며 서로 간섭하지 않는다. 반면, 전용 잠금은 말 그대로 배타적으로 작동한다. 즉, 쓰기 작업이 수행될 때, 다른 읽기 잠금과 기타 쓰기 잠금을 모두 차단한다. 
MySQL 환경에서는 동시성 제어를 위해 잠금이 항상 발생하며, 데이터 베이스가 정상적으로 작동하고 있다면 잠금 관리는 클라이언트가 알아차리지 못할 정도로 빠르게 수행된다.

 

잠금 세분화

 

동시성 제어를 가장 안전하게 하는 방법은 하나의 클라이언트만이 특정 리소스에 접근할 수 있게 하는 것이다. 가령, 유저 테이블을 변경하는 쿼리가 실행될 때, 유저 테이블 전체에 대해 전용 잠금을 하는 것이다. 하지만, 이 경우 트래픽이 많아질수록 데이터베이스에서의 병목이 심화될 수 밖에 없다. 더불어, 잠금 자체도 오버헤드를 발생시킨다. 잠금 설정 / 잠금 해제 여부 확인 / 잠근 해제 등 모든 잠금 작업에는 오버헤드가 존재하고, 잦은 잠금이 발생하면 오버헤드가 커지고 성능이 저하될 수 밖에 없다.
( 결국 모든 컴퓨터 프로그래밍이 그렇 듯, 안정성과 성능 사이에서  "트레이드 오프"를 갖는 셈이다 ) 

 

이를 개선할 수 있는 방법은 잠금을 세분화하는 것이다. 즉, 전체 리소스를 잠그는 대신, 변경할 데이터가 포함된 부분만 잠그는 것이다. 한 번에 잠그는 데이터 양을 최소화하면 지정된 리소스가 서로 충돌하지 않는 선에서 동시성 제어가 가능하다.

 

MySQL은 이에 대해 선택을 제공한다. 스토리지 엔진은 자체 잠금 정책과 세분화된 잠금 단위를 구현할 수 있다. 안정성이 중시되는 테이블에 대해서는 테이블 잠금을 설정하고, 성능이 중시되는 테이블에 대해서는 행 잠금만을 적용할 수도 있는 것이다. 

 

- 테이블 잠금

MySQL에서 사용할 수 있는 가장 기본적인 잠금 전략 + 가장 낮은 오버헤드
테이블에 쓰기가 발생할 때, 다른 모든 읽기 및 쓰기 작업을 차단하는 배타적 잠금

단순 조회에 대해서는 다른 읽기 잠금과 충돌하지 않는 읽기 잠금을 획득

특정 상황에서는 성능을 향상 시키기 위한 튜닝이 가능함. 가령, READ LOCAL 테이블 잠금은 일부 유형의 동시 쓰기 작업을 허용함.

 

- 행 잠금

가장 높은 동시성을 제공 + 가장 높은 오버헤드 ( 각 행 잠금을 추적, 정리해야하기 때문에 높은 오버헤드를 가진다 )

행 잠금은 서버가 아닌 스토리지 엔진에서 구현됨

트랜잭션

 

트랜잭션이란, 세분화된 단일 작업 단위로 처리되는 SQL문의 그룹이다. 데이터 베이스 엔진이 전체 명령문 그룹을 데이터베이스에 적용할 수 있을 때 적용하고, 충돌 등의 이유로 수행할 수 없을 때는 아예 적용을 막는다.

트랜잭션의 대표적인 예시는 은행 어플리케이션이다. 다음과 같은 순서로 승오가 월급 통장에서 저축 통장으로 돈을 이체한다고 가정해보자. 

1. 승오의 월급 통장 잔액이 200만원 이상인지 확인한다.
2. 승오의 월급 통장 잔액에서 200만원을 뺀다.
3. 승오의 저축 통장 잔액에 200만원을 추가한다.

이는 다음과 같은 쿼리로 나타낼 수 있다. 

START TRANSACTION;
SELECT balance FROM checking WHERE customer_id = 10233276;
UPDATE checking SET balance = balance - 200.00 WHERE customer_id = 10233276;
UPDATE savings SET balance = balance + 200.00 WHERE customer_id = 10233276;
COMMIT;

위 단계 중 하나라도 실패하면, 모든 단계가 롤백되도록 해야한다. 여기서 "실패"란, 모든 가능성을 열어 두어야 한다. 데이터 베이스 서버가 다운될 수도 있고, 다른 프로세스에 의해 월급 통장 잔고가 전부 날아가버릴 수도 있는 것이다. 어떠한 종류의 실패이든, 금전과 직접적으로 연결된다는 점에서 매우 치명적이다. 

그래서 MySQL InnoDB엔진에서는 ACID 트랜잭션을 통해 보증이 제공된다. ( 이는 MySQL의 가장 강력하고 성숙한 기능 중 하나이다 ) 특정 처리량의 트레이드 오프는 발생하겠지만, 잘 적용했을 때 어플리케이션 계층에서 불필요한 복잡한 로직을 생략할 수 있다. 

- ACID 란? 

Atomicity ( 원자성 )

트랜잭션은 분할될 수 없는 작업단위여야만 한다. 전부 완료 혹은 전부 실패만이 용인된다.

Consistency ( 일관성 )

데이터베이스는 항상 일관된 상태에서 다음 상태로 이동해야만 한다. 트랜잭션이 커밋되지 않으면 트랜잭션의 변경 사항은 데이터베이스에 반영되어서는 안된다.

Isolation ( 격리성 )

트랜잭션의 결과는 일반적으로 트랜잭션이 완료될 때까지 다른 트랜잭션에서 보이지 않는다. 

Durability ( 지속성 )

트랜잭션이 커밋되면, 변경 사항은 영구적이다. ( 실제로 지속성에는 다양한 수준이 있어서 약간 모호한 개념이라고 저자는 설명한다. 애초에 데이터 베이스 자체에 지속성이 100% 보장되었다면, 데이터베이스 백업이라는 프로세스는 불필요한 것이다 ) 

 

격리 수준

 

MySQL에 특화된 격리 이전에, ANSI SQL 표준은 네 가지 격리 수준을 정의하고 있다. 이 표준의 목적은 트랜잭션 내부와 외부에서 변경 사항이 있는지 여부를 규칙으로 정의하는 것이다. 잠금과 마찬가지로 격리 수준에 트레이드 오프가 있고, 일반적으로 격리 수준이 낮을수록 동시성이 높아지고 오버헤드가 줄어든다. 

 

- READ UNCOMMITTED

커밋되지 않은 트랜잭션의 결과를 볼 수 있음.

커밋 되지 않은 데이터를 읽는 행위는 더티 리드 ( Dirty Read ) 를 발생시키기에, 거의 사용되지 않음. 

 

- READ COMMITTED

MySQL을 제외한 대부분 데이터 베이스 시스템의 기본 격리 수준

트랜잭션이 시작된 후, 커밋된 다른 트랜잭션으로 인한 변경 사항을 계속해서 확인할 수 있으며, 커밋이 되지 않으면 변경 사항은 다른 사람에게 표시되지 않음.

예를 들어, 한 트랜잭션에서 유저를 서로 다른 시점에 두 번 조회한다고 가정하면, 그 사이에 유저를 업데이트하는 쿼리문이 커밋될 때, 두 시점에서 조회되는 유저 데이터는 일관적이지 않음. 이를 Nonrepeatable Read라고 함.

 

- REPEATABLE READ

위에 제기된 Nonrepeatable Read 문제를 해결하는 격리 수준으로, MySQL의 기본 트랜잭션 수준이기도 함.

트랜잭션이 읽는 모든 행이 동일한 트랜잭션 내에서는 동일하게 보이도록 보장함.

다만, 팬텀 리드를 허용한다는 문제가 남아있음. 팬텀 리드란, 특정 범위의 행을 선택하고 다른 트랜잭션이 해당 범위에 새로운 행을 삽입 하면, 다시 동일한 범위를 조회할 때 새로운 팬텀행이 표시됨. 

 

- SERIALIZABLE

가장 높은 수준의 격리 수준. 

읽는 모든 행에 잠금을 설정하기에, 많은 시간이 소요되고 잠금 경합이 발생할 수 있음.

어플리케이션의 특성 상, 데이터 안정성이 최우선이라고 한다면, 성능을 다소 희생하고 이 격리 수준을 택하기도 함. 

 

교착

 

교착 상태는 두 개 이상의 트랜잭션이 다른 순서로 동일한 리소스를 잠그려고 할 때 발생한다. 가령, 다음과 같은 두 가지 트랜잭션이 거의 동시에 실행된다고 가정해보자. 

START TRANSACTION;
UPDATE StockPrice SET close = 45.50 WHERE stock_id = 4 and date = '2002-05-01';
UPDATE StockPrice SET close = 19.80 WHERE stock_id = 3 and date = '2002-05-02';
COMMIT;
START TRANSACTION;
UPDATE StockPrice SET high = 20.12 WHERE stock_id = 3 and date = '2002-05-02';
UPDATE StockPrice SET high = 47.20 WHERE stock_id = 4 and date = '2002-05-01';
COMMIT;

첫 번째 트랜잭션이 실행될 때, stock_id = 4 이면서 date = '2002-05-01'인 데이터(A 데이터라고 지칭)가 잠금 처리된다. 그와 동시에 두 번째 트랜잭션이 실행되면서 stock_id = 3이면서 date = '2002-05-02'인 데이터(B 데이터라고 지칭)가 잠금 처리된다. 여기까지는 문제될 사항이 따로 없다. 

하지만 다음 실행부터는 문제가 된다. 첫 번째 트랜잭션의 다음 줄은 B 데이터를 업데이트 하려하는데, 두 번째 트랜잭션에 의해 잠금 처리가 되어 있기에 첫 번째 트랜잭션은 두 번째 트랜잭션의 커밋을 기다린다. 두 번째 트랜잭션의 경우, 다음 줄을 실행하기 위해서는 A 데이터에 접근해야하는데 첫 번째 트랜잭션에 의해 락이 걸려있어서 첫 번째 트랜잭션의 커밋을 기다리게 된다. 결국, 두 트랜잭션은 서로의 커밋을 영원히 기다리는 교착 상태에 도달한다. 

 

교착 상태의 해결을 위해 데이터베이스 시스템은 다양한 형태의 교착 상태 탐지 및 시간 초과 기능을 구현하고 있다. MySQL의 InnoDB 스토리지 엔진은 정교한 시스템을 가지고 있어 순환 종속성을 감지하고 오류를 즉시 반환할 수 있다. InnoDB가 현재 교착 상태를 처리하는 방법은 배타적 행 잠금이 가장 적은 트랜잭션을 롤백하는 것이다. ( 쿼리가 잠금 대기 시간 제한을 초과했을 때 다른 쿼리를 포기해버리는 것은 서비스에 직접적인 영향을 줄 수 있기에 그리 선호되지 않는다 )

 

일단 교착 상태가 발생하면 트랜잭션의 일부 또는 전체를 롤백하는 것은 불가피하다. 이것은 트랜잭션 이라는 기능이 갖는 특성이기에 어플리케이션은 이를 처리하게 설계되어야만 한다.

 

트랜잭션 로깅

 

트랜잭션 로깅은 트랜잭션을 효율적으로 만드는 데에 일조한다. 변경 사항이 발생할 때마다 스토리지 엔진이 디스크의 테이블을 직접 업데이트하는 대신 데이터의 메모리 내 복사본을 변경하는 방식으로 동작시킬 수 있으며, 이는 매우 빠르게 이루어질 수 있다. 스토리지 엔진은 트랜잭션 로그에 변경 사항을 디스크에 기록하기에 내구성을 갖기도 한다. ( 다만, 데이터 베이스 리소스를 더 사용해야한다는 점에서 코스트가 더 들 수 있다고 본다 )

 

MySQL에서의 트랜잭션 ( InnoDB 기준 )

 

- AUTOCOMMIT

 

기본적으로 단일 INSERT, UPDATE, DELETE 문은 트랜잭션으로 처리되어 즉시 커밋된다. 이를 AUTOCOMMIT 모드라고 한다. 이 모드를 SET 명령어를 사용하여 활성 / 비활성화할 수도 있다. ( 디폴트로는 활성화되어 있다 ) 비활성화를 할 경우, 커밋 또는 롤백을 하기 전까지 항상 트랜잭션에 머물러 있게 된다.

 

MySQL에서는 트랜잭션 내에서 특정 명령들에 대해 실행하기 전에 트랜잭션을 커밋하는 경우도 있다. 대표적으로 ALTER TABLE 과 같은 DDL 명령어 혹은 LOCK TABLE과 같은 구문들이 있다.

 

MySQL에서는 다음 쿼리를 통해 트랜잭션의 기본 격리 수준을 설정할 수도 있다. 

SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;

 

- 트랜잭션에서 스토리지 엔진 혼합

 

MySQL은 서버 수준에서 트랜잭션을 관리하지 않는다. 대신, 기본 스토리지 엔진이 트랜잭션을 구현한다. 이 말인 즉슨, 단일 트랜잭션에서 서로 다른 엔진을 안정적으로 혼용할 수 없다는 이야기이다. 

 

가령, 트랜잭션에서 MyISAM 엔진으로 구성된 테이블과 InnoDB 엔진으로 구성된 테이블을 혼용하는 경우를 생각해보자. 해피 케이스에 대해서 트랜잭션이 제대로 작동할 수도 있다. 하지만, 어떠한 엣지 케이스로 인해 롤백이 필요하다면? 비트랜잭션 테이블에 대한 변경 사항은 취소할 수 없게 되고, 결국 전체 트랜잭션이 무의미해지게 된다. 따라서 어플리케이션 로직에서 스토리지 엔진의 혼용을 피하는 것은 중요하고,  그에 앞서서 스토리지 엔진을 혼용하여 설계하지 않는 것 역시도 중요하다고 볼 수 있다.

 

- 암시적 잠금과 명시적 잠금

 

InnoDB는 2단계 잠금 프로토콜을 사용한다. 트랜잭션 중 언제든지 잠금을 확득할 수 있고, 커밋 또는 롤백 명령어가 실행되기 전까지 잠금을 해제하지 않는다. InnoDB 는 격리 수준에 따라 잠금을 자동으로 처리하며, 잠금 매커니즘은 암시적이다. 

 

다만, InnoDB는 다음과 같은 명시적 잠금 역시 지원한다. 물론 이는 일반적으로 피해야하는 안티 패턴이라고 저자는 말한다. 더불어 InnoDB는 트랜잭션에 행 수준의 잠금을 지원하기에, 따로 테이블을 잠그는 LOCK TABLES .. 와 같은 쿼리 사용을 피하라고 한다.

SELECT ... FROM UPDATE;

 

다중 버전 동시성 제어 ( MVCC )

 

MySQL 스토리지 엔진은 단순한 행 잠금 매커니즘을 사용하지 않는다. 대신, MVCC로 불리는 동시성을 높이는 기술과 함께 행 수준 잠금을 사용한다. 이는 Oracle, PostgreSQL 등 다른 데이터 베이스 시스템에도 모두 존재하기는 하나, 이에 대해 표준은 없기에 각각이 상당한 차이를 나타낸다.

 

MVCC는 특정 시점에 존재했던 데이터의 snapshot을 사용하여 작동한다. 즉, 트랜잭션은 실행 시점에 관계 없이 데이터를 일관되게 볼 수 있다. 더불어 트랜잭션마다 동일한 테이블에서 다른 데이터를 동시에 볼 수도 있다. 스토리지 엔진 별로 MVCC의 구현은 다르다. InnoDB 의 경우, 트랜잭션마다 트랜잭션 ID를 할당하여 MVCC를 구현한다. ID는 트랜잭션이 데이터를 처음 읽을 때 할당되며, 트랜잭션 내에서 레코드를 수정하면 변경 내용을 되돌리는 방법을 설명하는 언두( Undo ) 레코드가 언두 로그에 기록되고 트랜잭션의 롤백 포인터가 언두 로그 레코드를 가르키게 된다. ( 이것이 트랜잭션을 롤백하는 방식이라고 볼 수 있다 )

 

예를 들어, 트랜잭션 A와 트랜잭션 B 가 모두 유저 테이블에 접근하는 상황을 가정해보자.

트랜잭션 A가 유저 테이블에 쓰기 작업을 수행하면, InnoDB 가 트랜잭션 ID가 A인 레코드를 언두 로그에 쌓고, 트랜잭션 A의 롤백 포인터는 해당 언두 로그를 가리키게 된다. 이 때, 트랜잭션 B가 유저 테이블을 조회하면, InnoDB는 트랜잭션 ID가 B가 나올 때까지 언두 로그 레코드를 추적하고, 적용한다. 즉, A 트랜잭션이 커밋되기 이전의 스냅샷을 B 트랜잭션이 조회 수 있게되는 셈이다. 한편, 트랜잭션 A는 본인이 수행하는 모든 쓰기 작업 및 언두 로그를 리두( Redo ) 로그로 기록하고, 서버 충돌 복구 프로세스의 일부로 활용될 수 있다. 

MVCC의 장점은 데이터를 최대한 빨리 읽어 기준에 맞는 행만 선택하여 높은 동시성을 제공하는 데에 있다. 다만, 단점은 각 행에 더 많은 데이터를 저장해야 하고, 행을 검사할 때 더 많은 작업을 수행해야함에 있다. 

MVCC는 REPEATABLE READ와 READ COMMITTED 격리 수준에서만 작동한다. 

 

복제

 

MySQL은 한 노드가 사용하는 쓰기를 추가 노드에 배표하는 "복제" 방식을 제공한다. 소스 노드에 쓰기 작업을 수행할 때, 새 데이터를 보내는 복제 클라이언트로 로그인된 레플리카에 대한 스레드가 별도로 존재한다. 운영 환경에서는, 재해 복구 계획을 위해 복제를 사용하고 여러 위치에 분산되어 있는 3개 이상의 레플리카를 보유하는 것이 이상적이다. 

 

데이터 파일 구조

 

8.0 버전부터 MySQL은 테이블 메타데이터를 테이블의 .ibd 파일에 포함된 데이터 딕셔너리로 재설계했다. 

이를 통해, 테이블 구조 지원 트랜잭션 및 원자 데이터 정의 변경에 대한 정보가 내부적으로 생성될 수 있다.

 

InnoDB 엔진

 

InnoDB는 MySQL의 기본 트랜잭션 스토리지 엔진이며, 가장 중요하고 유용한 엔진이다. 일반적으로 롤백되지 않고 완료되는 많은 단기 트랜잭션을 처리하도록 설계되었으며, 성능과 자동 충돌 복구로 인해 비트랜잭션 스토리지 요구 사항에도 널리 사용된다. InnoDB는 데이터를 모아 테이블 스페이스로 알려진 일련의 데이터 파일에 저장한다. 여기서 테이블 스페이스란, 기본적으로 InnoDB가 자체적으로 관리하는 블랙박스이다.

 

InnoDB는 MVCC를 사용하여 높은 동시성을 가지며, 네 가지 SQL 표준 격리 수준을 모두 구현하고 있다. REPEATABLE READ 를 기본 격리 수준을 가지며, 이 격리 수준에서 팬텀 리드를 방지하는 next-key 잠금 전략을 사용한다. 

더보기

next-key 잠금이란?

쿼리에서 터치한 행만 잠그는 대신, 인덱스 구조의 공백도 잠궈서 팬텀이 삽입되는 것을 방지하는 방식

InnoDB의 인덱스는 클러스터형 인덱스로 구성되며, 기본 키 검색을 매우 빠르게 수행할 수 있다. 그러나 보조 인덱스를 구성할 때는 기본 키 열이 포함되게 구성하여, 기본 키가 크면 다른 인덱스도 커지게 된다. 따라서 테이블에 인덱스가 많을 경우, 기본 키를 작게 만들도록 신경 써야 한다.

InnoDB에는 다양한 내부 최적화가 존재한다. 가령, 디스크에서 데이터를 미리 가져오기 위한 예측 사전 검색, 매우 빠른 검색을 위해 메모리에 해시 인덱스를 자동으로 구축하는 적응형 해시 인덱스, 삽입 속도를 높이는 버퍼 삽입 등이 있다. 

 MySQL 5.6부터는 InnoDB에 온라인 DDL이 도입되어, 8.0 이상부터는 확장되었다. 이는 내부 스키마를 변경할 때, 전체 테이블 잠금 없이 변경을 가능케하여, 테이블의 라이브 운영성을 크게 향상시켰다.

이외에도  JSON 문서 지원, Atomic DDL 등 InnoDB는 다양한 기능을 더 갖추어 나가고 있다. 

 

Atomic DDL 이란?
ALTER TABLE ... 과 같은 DDL 문에 대해 언두/리두 로그를 생성함으로써 DDL도 트랜잭션처럼 수행될 수 있는 기능. 이는 InnoDB의 입증된 설계로 MySQL 서버의 작업으로 확장된 영역이다.