
MySQL 서버는 크게 MySQL 엔진과 스토리지 엔진으로 구분할 수 있다.
MySQL 엔진은 사람의 머리와 같은 역할로, 쿼리를 최적화 하고 실행계획을 수립한다.
스토리지 엔진은 사람의 손발과 같은 역할로, 실제 데이터를 디스크 스토리지에 읽고 쓰는 역할을 맡는다.
스토리지 엔진은 핸들러 API를 만족하면 누구든지 구현해서 MySQL 서버에 추가해서 사용이 가능하다. 또한 여러 스토리지 엔진을 동시에 사용할 수 있으며, 테이블마다 다른 스토리지 엔진을 사용할 수 있다.

MySQL 엔진은 클라이언트의 접속 및 쿼리 요청을 처리하는 커넥션 핸들러와 SQL 파서 및 전처리기, 최적화된 실행을 위한 옵티마이저가 중심을 이룬다.
SQL 파서
: 들어온 SQL을 토큰으로 분리하여 트리 형태의 구조로 만들어낸다. 이 과정에서 기본 문법 오류들이 발견되고, 사용자에게 오류 메시지를 전달한다.
전처리기
: 파서 트리를 기반으로 구조적인 문제를 파악한다. 파싱된 각 토큰을 실제 객체와 매핑하고, 존재 여부와 접근 권한 등을 확인한다. 존재하지 않거나, 접근 권한이 없는 경우 이 단계에서 걸러진다.
옵티마이저
: DBMS의 두뇌라고 할 수 있는 옵티마이저는 사용자의 쿼리를 가장 저렴한 비용으로 가장 빠르게 처리할 수 있도록 변환하고, 실행 계획을 수립한다.
쿼리 실행기(실행 엔진)
: 옵티마이저에 의해 만들어진 각 계획대로 스토리지 엔진(핸들러)에 직접 수행하는 역할을 한다. 실행 계획의 각 단계에서 만들어진 결과를 다음 단계의 입력으로 연결하는 역할을 수행한다.
스토리지 엔진은 핸들러 API를 구현하며, 디스크에 읽고 쓰는 역할을 담당한다.


핸들러 API는 SHOW GLOBAL STATUS LIKE 'Handler%;'명령어로 확인이 가능하며, 얼마나 많은 데이터 작업이 있었는지 확인할 수 있다.
스토리지 엔진은 InnoDB, MyISAM, MEMORY 등이 있으며, 그 중 가장 많이 사용되는 엔진은 InnoDB 스토리지 엔진이다.
각 스토리지 엔진은 성능 향상을 위해 키 캐시(MyISAM)나 버퍼 풀(InnoDB)과 같은 기능을 내장하고 있다.

MySQL 서버는 프로세스 기반이 아닌 스레드 기반으로 동작하며, 크게 포그라운드(Foreground) 스레드, 백그라운드(Background) 스레드로 구분할 수 있다.
MySQL 서버에서 실행 중인 스레드 목록은 performance_schema 데이터베이스의 threads 테이블을 통해 확인할 수 있다.

포그라운드 스레드는 최소한 서버에 접속된 클라이언트의 수만큼 존재하며, 주로 각 클라이언트 사용자가 요청하는 쿼리 문장을 처리한다.
클라이언트가 MySQL에 접속하면 서버는 클라이언트의 요청을 처리해 줄 스레드를 생성해 그 클라이언트에게 할당한다.
포그라운드 스레드는 데이터를 MySQL의 데이터 버퍼나 캐시로부터 가져오며, 버퍼나 캐시에 없는 경우 직접 디스크의 데이터나 인덱스 파일로부터 데이터를 읽어와서 작업을 처리한다.
MyISAM 스토리지 엔진은 디스크 쓰기 작업까지 포그라운드 스레드가 처리하지만,
InnoDB 스토리지 엔진은 데이터 버퍼나 캐시까지만 포그라운드 스레드가 처리하고, 나머지 버퍼로부터 디스크까지의 쓰기 작업은 백그라운드 스레드가 처리한다.

Spring-boot 웹 애플리케이션을 하나 띄웠을 때, 위와 같이 포그라운드 스레드가 10개 추가로 생성된 것을 확인할 수 있다.
그런데 왜 포그라운드 스레드가 10개나 생성된 것일까?
그 이유는 데이터베이스 커넥션 풀(Connection pool) 설정 때문이다.
HikariCP(Spring boot 기본 데이터베이스 커넥션 풀링 라이브러리)는 최대 성능을 보장하기 위해 초기화 시 미리 커넥션을 생성하고 유지하는데, 이 동작이 MySQL 서버에 연결된 활성 스레드 수를 증가시킨다.
애플리케이션 시작 시, 기본적으로 10개의 커넥션을 생성하여 풀에 보관하고, MySQL 서버는 이 10개의 커넥션을 유지하기 위해 10 개의 포그라운드 스레드를 생성하는 것이다.
즉, MySQL 서버는 기본적으로 1:1로 커넥션과 스레드를 매핑한다.
Spring boot의 데이터베이스 커넥션 풀 설정
spring:
datasource:
hikari:
maximum-pool-size: 10 //최대 커넥션 수
minimum-idle: 5 //최소 유휴 커넥션 수
위와 같이 커넥션 풀 설정이 가능하며, 이에 따라 MySQL 서버의 포그라운드 스레드 수도 달라진다.

애플리케이션 시작 시, minumum-idle 만큼 5개의 포그라운드 스레드만 생성된 것을 확인할 수 있다.
만약 애플리케이션이 동시에 5개의 커넥션을 모두 사용하면서 새로운 커넥션을 요청한다면, 최대 10개까지 커넥션을 새롭게 생성할 것이며, 그에따라 MySQL의 포그라운드 스레드 수도 늘어날 것이다.
InnoDB는 다음과 같이 여러 작업이 백그라운드로 처리된다.
InnoDB를 포함한 일반적인 상용 DBMS에는 대부분 쓰기 작업을 버퍼링해서 일괄 처리하는 기능이 탑재되어있다.
이러한 이유로 InnoDB에서는 INSERT, UPDATE, DELETE 쿼리로 데이터가 변경되는 경우 데이터가 디스크의 데이터 파일로 완전히 저장될 때까지 기다리지 않아도 된다.
(이는 백그라운드 쓰기 스레드가 처리한다)

MySQL에서 사용되는 메모리 공간은 크게 글로벌 메모리 영역과 로컬 메모리 영역으로 나뉜다.
글로벌 메모리 영역은 클라이언트 스레드의 수와 무관하게 하나의 메모리 공간만 할당되고, 모든 스레드에 의해 공유된다.
로컬(세션) 메모리 영역은 클라이언트 스레드가 쿼리를 처리하는 데 사용되는 영역이다.

MySQL의 독특한 구조 중 대표적인 것은 플러그인 모델이다.
각 스토리지 엔진을 플러그인의 형태로 사용할 수 있으며 뿐만 아니라 검색 엔진을 위한 검색어 파서, 인증 기능도 모두 플러그인으로 구현되어 제공된다.
사용자가 직접 스토리지 엔진 플러그인을 개발하더라도, 사람의 머리 역할을 하는 MySQL 엔진은 그대로 동작한다.
따라서 이는 DBMS 전체 기능이 아닌 일부분의 기능만 수행하는 엔진을 작성하는 것이다.
MySQL 8.0 부터는 기존의 플러그인 아키텍처를 대체하기 위해 컴포넌트 아키텍처가 지원된다.
플러그인의 단점은 다음과 같다.
컴포넌트는 이러한 단점들을 보완해서 구현되었다.