# Real MySQL 8.0 1권

『Real MySQL 8.0』은 『Real MySQL』을 정제해서 꼭 필요한 내용으로 압축하고, MySQL 8.0의 GTID와 InnoDB 클러스터 기능들과 소프트웨어 업계 트렌드를 반영한 GIS 및 전문 검색 등의 확장 기능들을 추가로 수록했다. 또한 단순 SQL 문법이나 쿼리 작성보다는 MySQL 서버를 활용하는 프로젝트에서 꼭 필요한 경험과 지식을 전달하는 데 집중했다.

# 4. 아키텍처

# MySQL 엔진 아키텍처

## MySQL 엔진 아키텍처

<img src="https://wiki.luigi99.cloud/uploads/images/gallery/2026-01/BOfzTFep6noBsQOs-image-1769398749956.png" width="50%">

- MySQL 서버는 사람의 머리 역할을 담당하는 **MySQL 엔진**과 손발 역할을 담당하는 **스토리지 엔진**으로 구분
- 스토리지 엔진의 **핸들러 API**를 만족하면 누구나 **스토리지 엔진을 구현해** MySQL 서버에 추가해서 사용 가능

---

## MySQL 엔진

- 클라이언트로부터의 접속 및 쿼리 요청을 처리하는 **커넥션 핸들러, SQL 파서, 전처리기, 옵티마이저**가 중심을 이룸
- 표준 SQL 문법을 지원해 **표준 문법**을 지켜 작성된 쿼리는 **타 DBMS와 호환**되어 실행 가능

---

## 스토리지 엔진

- 실제 데이터를 **디스크 스토리지에 저장**하거나 **데이터를 읽어오는 역할**을 수행
- MySQL 엔진은 하나만 사용할 수 있지만 **스토리지 엔진은 여러 개를 동시에 사용 가능**
- 다음 명령어를 통해 테이블에 사용할 스토리지 엔진을 지정할 수 있음

  ```mysql
  CREATE TABLE test_table (fd1 INT, fd2 INT) ENGINE=INNODB;
  ```

---

## 핸들러 API

- MySQL 엔진의 쿼리 실행기에서 **데이터를 쓰거나 읽을 때** 각 스토리지 엔진에 요청을 하는데 이를 **핸들러(Handler) 요청**으로 부름
- 핸들러 API를 통해 레코드 작업이 얼마나 수행됐는지 확인하는 명령어
  ```mysql
  SHOW GLOBAL STATUS LIKE 'Handler%';
  ```

# MySQL 스레딩 구조

## MySQL 스레딩 구조

<img src="https://wiki.luigi99.cloud/uploads/images/gallery/2026-01/EfmKdzgtVilJr6P8-image-1769486114185.png" width = "70%">

- MySQL 서버는 프로세스가 아닌 **스레드 기반**으로 동작
- 스레드는 크게 **Foreground 스레드**와 **Background 스레드** 두 종류로 구분
- MySQL 서버의 실행 중인 스레드 목록 조회 명령어

  ```mysql
  SELECT thread_id, name, type, processlist_user, processlist_host
  FROM performance_schema.threads ORDER BY type, thread_id;
  ```

- **사용자의 요청을 처리**하는 Foreground 스레드는 **`thread/sql/one_connection`** 스레드
- Background 스레드의 개수는 MySQL 서버 설정으로 조절 가능

---

## Foreground 스레드 (클라이언트 스레드)

- MySQL 서버에 **연결된 클라이언트의 수**만큼 존재함
  - 각 클라이언트 **유저가 요청한 쿼리 문장**을 처리
- 사용자가 작업을 마친 후 커넥션을 종료하면 해당 커넥션을 담당하던 스레드는 **스레드 캐시**로 돌아감
  - 단, 스레드 캐시에 **일정 개수 이상의 대기 중인 스레드**가 존재하면 캐시에 넣지 않고 스레드를 종료시킴
  - 스레드 캐시에서 **항상 일정한 스레드 개수 유지**
  - 유지할 스레드 개수는 **`thread_cache_size`** 시스템 변수로 설정 가능
- Foreground 스레드는 데이터를 MySQL의 **데이터 버퍼**나 **캐시**로부터 조회
  - 버퍼나 캐시에 없는 경우 **직접 디스크의 데이터나 인덱스 파일로부터 조회한 후 작업 처리**
  - MyISAM 테이블은 **디스크 쓰기 작업**까지 Foreground 스레드가 처리
  - InnoDB 테이블은 **데이터 버퍼**와 **캐시**까지는 Foreground 스레드가 처리하고 **디스크 기록은 Background 스레드가 처리**

---

## Background 스레드

- InnoDB에서 **여러 가지의 작업**을 Background 스레드로 처리
  - Insert Buffer를 병합하는 스레드
  - 로그를 디스크로 기록하는 스레드
  - InnoDB 버퍼 풀의 데이터를 디스크에 기록하는 스레드
  - 데이터를 버퍼로 읽어 오는 스레드
  - 잠금이나 데드락을 모니터링하는 스레드
- 가장 중요한 스레드는 **로그 스레드**와 버퍼의 데이터를 **디스크로 기록하는 쓰기 스레드**
- MySQL 5.5 버전부터 **쓰기 스레드**와 **읽기 스레드**의 개수를 2개 이상 지정할 수 있음
  - `innodb_read_io_threads`: **데이터를 주로 클라이언트 스레드에서 처리**되기에 많이 설정할 필요 없음
  - `innodb_write_io_threads`: 많은 작업을 Background로 처리하기에 **일반적인 내장 디스크 활용 시 2~4개 권장**
- 사용자의 요청을 처리하는 도중 데이터 쓰기 작업은 지연(버퍼링)되어 처리 가능
- 데이터의 읽기 작업은 절대 지연될 수 없음
  - 예시: SELECT 쿼리 실행 후 요청된 SELECT 응답을 10분 뒤에 돌려주는 DBMS는 존재하지 않음
- 일반적인 상용 DBMS는 대부분 쓰기 작업을 버퍼링해 일괄 처리하는 기능이 탑재됨
  - 단, 예외로 MyISAM의 경우 사용자 스레드가 쓰기 작업까지 함께 처리하도록 설계
- InnoDB에서는 `INSERT`, `UPDATE`, `DELETE` 쿼리로 데이터가 변경되는 경우 데이터가 디스크에 완전히 기록될 때까지 기다리지 않아도 됨
  - MyISAM에서는 일반적인 쿼리는 쓰기 버퍼링 기능 사용 불가

# 메모리 할당 및 사용 구조

## 메모리 할당 및 사용 구조

<img src="https://wiki.luigi99.cloud/uploads/images/gallery/2026-01/RmzFklXV1jdeP8wy-image-1769486235900.png" width="70%">

- MySQL 메모리 공간은 **글로벌 메모리 영역**과 **로컬 메모리 영역**으로 구분할 수 있음
- **글로벌 메모리 영역**은 MySQL 서버가 시작되면서 **운영체제로부터 할당**받음
- 글로벌 메모리 영역과 로컬 메모리 영역은 **스레드가 공유해서 사용하는 공간인지 여부**에 따라 구분됨

---

## 글로벌 메모리 영역

- 일반적으로 클라이언트 **스레드의 수와 무관**하게 하나의 메모리 공간만 할당
  - 필요에 따라 2개 이상의 메모리 공간을 할당받을 수 있으나 클라이언트 스레드 수와 무관
  - 생성된 글로벌 영역이 N개라 해도 **모든 스레드에 의해 공유됨**
- **대표적인 글로벌 메모리 영역**
  - 테이블 캐시
  - InnoDB 버퍼 풀
  - InnoDB 어댑티브 해시 인덱스
  - InnoDB 리두 로그 버퍼

---

## 로컬 메모리 영역

- **세션 메모리 영역**이라 표현하며 MySQL 서버에 존재하는 **클라이언트 스레드가 쿼리를 처리하는 데 사용하는 메모리 영역**
  - 대표적으로 **커넥션 버퍼**와 **정렬 버퍼** 등이 존재함
- 클라이언트가 MySQL 서버에 접속하면 클라이언트 커넥션으로부터의 요청 처리를 위해 스레드를 하나씩 할당
  - 클라이언트 스레드가 사용하는 메모리 공간이라고 해서 클라이언트 메모리 영역이라고 부름
  - 클라이언트와 MySQL 서버와의 커넥션 = 세션 (세션 메모리 영역)
- 각 클라이언트 **스레드별로 독립적으로 할당**되며 스레드간 공유가 이뤄지지 않음
- 각 쿼리의 용도별로 **필요할 때만 공간이 할당**되고 필요하지 않으면 MySQL이 메모리 공간을 할당하지 않음
  - 커넥션이 열려 있는 동안 계속 할당된 상태로 남아 있는 공간이 존재함
    - 커넥션 버퍼나 결과 버퍼
  - 쿼리를 실행하는 순간에만 할당한 후 다시 해제하는 공간이 존재함
    - 소트 버퍼나 조인 버퍼
- **대표적인 로컬 메모리 영역**
  - 정렬 버퍼
  - 조인 버퍼
  - 바이너리 로그 캐시
  - 네트워크 버퍼

# 플러그인 스토리지 엔진 모델

## 플러그인 스토리지 엔진 모델

<img src="https://wiki.luigi99.cloud/uploads/images/gallery/2026-01/0KZ8PUuuCeCAKBOs-image-1769657785226-36-20.png" width="80%">

- 전문 검색 엔진을 위한 검색어 파서