본문 바로가기

DB/MySQL

[ Real MySQL 8.0. 1 ] 2주차 스터디 (4장)

 위 포스트는 "Real MySQL 8.0 1" 책 Chapter 4장 내용을 학습한 후 정리한 글입니다.

Real MySQL 8.0 1권 : 알라딘

《Real MySQL》을 정제해서 꼭 필요한 내용으로 압축하고, MySQL 8.0의 GTID와 InnoDB 클러스터 기능들과 소프트웨어 업계 트렌드를 반영한 GIS 및 전문 검색 등의 확장 기능들을 추가로 수록했다.

www.aladin.co.kr

 
 

Chapter 04. 아키텍처 

📌 MySQL 서버 = MySQL엔진 + 스토리지 엔진
📌 스토리지 엔진이 핸들러 API 만족 -> 누구든 스토리지 엔진 구현 가능 -> MySQL 서버에 추가해서 사용 가능

 

4.1 MySQL 엔진 아키텍처 

4.1.1 MySQL의 전체 구조


 
MySQL은 대부분의 프로그래밍 언어로부터 접근 방법을 모두 지원한다.
표준 드라이버를 이용해 모든 언어로 MySQL 서버에서 쿼리를 사용할 수 있게 지원한다는 의미이다.
 
 

1️⃣ MySQL 엔진 (MySQL Engine)

MySQL의 전체적인 핵심 엔진

  • 사용자의 SQL 쿼리(SELECT, INSERT 등)를 해석하고 실행 계획을 수립하는 역할
  • 실행할 때, 어떤 스토리지 엔진을 사용할지 결정하고, 스토리지 엔진에게 데이터를 요청
  • 핸들러 API(Handler API)를 통해 스토리지 엔진과 연결

 
📌 구성 요소

    • SQL 파서(Parser): 사용자가 입력한 SQL 문장을 분석해서 처리
    • 커넥션 핸들러 (Connection Handler) : 사용자가 MySQL 서버에 연결할 때, 해당 연결을 관리하고 새로운 스레드를 생성하거나 기존 스레드를 재사용하여 SQL 쿼리 처리 프로세스를 시작.
    • 전처리기 (Preprocessor) : SQL 쿼리의 추가적인 변환을 처리
    • 옵티마이저(Optimizer): 최적의 실행 계획을 세우는 역할

 

MySQL 엔진레스토랑의 매니저이다.
손님(사용자)이 "김치찌개 주세요!"(SQL 쿼리)를 요청하면, 종업원에게 일을 시켜 주방(스토리지 엔진)으로 가서 요리(데이터)를 받아다 준다.

 
 
 
2️⃣ 핸들러 API (Handler API)

MySQL 엔진과 스토리지 엔진을 연결하는 인터페이스(API)

  • MySQL 엔진이 직접 데이터를 저장하거나 불러오는 게 아니라, 핸들러 API를 통해 스토리지 엔진에게 요청
  • 마치 운전대가 자동차 엔진을 조작하는 것처럼, 핸들러 API는 MySQL 엔진이 스토리지 엔진을 다룰 수 있도록 도와줌

📌 핸들러 API의 기능

  • 데이터를 삽입, 조회, 삭제, 업데이트할 수 있도록 도와줌
  • 여러 스토리지 엔진을 지원할 수 있도록 추상화된 구조 제공

 

핸들러 API는 종업원이 주방과 소통하는 인터폰이다.
종업원이 "김치찌개 하나 주세요!"(쿼리 실행)를 요청하면, 인터폰(핸들러 API)을 통해 주방(스토리지 엔진)에 전달된다.
주방에서 "김치찌개 하나 나왔습니다!"(데이터 처리)라고 응답하면, 종업원은 그 음식을 손님에게 가져다준다.

 
 
 
3️⃣ 스토리지 엔진 (Storage Engine)

데이터를 저장하고 관리하는 역할을 하는 컴포넌트

  • MySQL 엔진이 핸들러 API를 통해 요청하면, 스토리지 엔진이 데이터를 저장하거나 불러옴
  • MySQL은 여러 개의 스토리지 엔진을 지원
  • SHOW GLOBAL STATUS LIKE 'Handler%'
    • 핸들러 API를 통해 얼마나 많은 데이터(레코드) 작업이 있었는지 확인

 
📌 대표적인 스토리지 엔진

  • InnoDB: 트랜잭션 지원, ACID 보장, 외래 키(FK) 지원 (MySQL 기본 엔진)
  • MyISAM: 빠른 읽기 속도, 트랜잭션 미지원 (과거에 많이 사용됨)
  • Memory: 데이터를 RAM에 저장, 속도가 빠름, 서버 재부팅 시 데이터 사라짐
  • CSV: 데이터를 CSV 파일로 저장

 

스토리지 엔진주방이다.
김치찌개(데이터)를 직접 조리(처리)하고, 종업원에게 전달해 준다.
그리고 어떤 스토리지 엔진을 쓰느냐에 따라 음식(데이터)의 특성이 달라진다.
예를 들어, InnoDB는 안전하지만 느린 음식, Memory 엔진은 빠르지만 금방 사라지는 음식 같은 차이가 있다.

 
 

 
📌 전체적인 구조 정리

사용자 (User)  
  ├──> MySQL 엔진 (SQL 처리, 최적화, 요청 관리)  
  │       ├──> 핸들러 API (스토리지 엔진과의 인터페이스)  
  │       │       ├──> InnoDB (기본 저장 엔진)  
  │       │       ├──> MyISAM (빠른 읽기 전용 엔진)  
  │       │       ├──> Memory (RAM 기반 엔진)

 
1️⃣ 손님(사용자)이 "김치찌개 주세요!"(SQL 실행)라고 요청
2️⃣ 매니저(MySQL 엔진)가 종업원(스레드)에게 지시
3️⃣ 종업원(스레드)이 인터폰(핸들러 API)을 이용해 주방(스토리지 엔진)에 요청
4️⃣ 주방(스토리지 엔진)에서 김치찌개(데이터)를 조리 후 종업원에게 전달
5️⃣ 종업원(스레드)이 음식을 손님(사용자)에게 가져다줌
 
 

  • MySQL 엔진: SQL 실행 및 관리
  • 핸들러 API: MySQL 엔진과 스토리지 엔진을 연결
  • 스토리지 엔진: 데이터를 저장하고 관리

 
 
 

4.1.2 MySQL 스레딩 구조


 
 
MySQL 서버는 스레드 기반 으로 작동한다.
하나의 프로세스 안에서 여러 개의 스레드가 실행되는 구조이며,
즉, 클라이언트가 MySQL 서버에 접속하면 새로운 스레드가 생성되어 각각의 요청을 처리한다는 의미이다.
 

🌟 프로세스 
:  실행 중인 프로그램
ex ) 크롬을 실행하면 OS가 크롬 프로세스를 메모리에 로드하고 CPU가 명령을 실행함


🌟 스레드 
: 프로세스 안에서 실행되는 작은 작업 단위

  프로세스 스레드
정의 실행 중인 프로그램 프로세스 내부에서 실행되는 작업 흐름
메모리 프로세스마다 독립된 메모리 사용 같은 프로세스 내에서 메모리를 공유
통신 방식 프로세스 간 통신(IPC)은 상대적으로 느림 같은 프로세스 내에서 빠르게 데이터 공유 가능
예시 크롬 브라우저 실행 크롬의 탭, 렌더링, 사용자 입력 처리

 
 
앞서 4.1.1의 식당 비유 예시를 다시 살펴보면,
MySQL 엔진이 종업원을 관리하는 매니저, 실제 일하는 종업원을 스레드(포그라운드/백그라운드)라고 할 수 있다.
스레드 구조는 MySQL 엔진 내부에서 동작하며, 클라이언트의 요청을 처리하고 시스템을 관리하는 역할을 한다.

[사용자(Client)]
    │
    ▼
[MySQL 엔진]  ← SQL 해석, 실행 계획 수립
    │
    ├── 포그라운드 스레드 (사용자 요청 처리)
    ├── 백그라운드 스레드 (트랜잭션, 복제, 캐싱 관리)
    │
    ▼
[스토리지 엔진] ← 실제 데이터 저장/조회

 
작업을 수행하는 실행 단위 개념을 크게 포그라운드(Foreground) 스레드, 백그라운드(Background) 스레드로 구분할 수 있으며,
MySQL 서버에서 실행 중인 스레드의 목록은 데이터베이스의 threads 테이블을 통해 확인할 수 있다.
 
 
 

1️⃣ 포그라운드 스레드(클라이언트 스레드)

클라이언트(사용자)의 요청을 직접 처리하는 스레드

  • 클라이언트가 MySQL 서버에 접속하면, 클라이언트마다 하나의 전용 스레드(포그라운드 스레드)가 생성됨
  • 성능 최적화를 위해 스레드 캐시, 버퍼, 캐시 등을 활용함.
  • 스레드 캐시가 설정되어 있으면, 기존 스레드를 재사용하여 빠르게 응답 가능

 
 
1)  클라이언트(사용자)가 MySQL 서버에 접속 (커넥션 생성)

  • 손님이 레스토랑에 들어와 자리를 배정받음.
  • MySQL에서는 max_connections 설정값만큼 최대 커넥션을 유지할 수 있음.

2)  MySQL 엔진이 포그라운드 스레드를 할당

  • 종업원(포그라운드 스레드)이 배정되어 손님의 주문(SQL)을 받음.
  • 이때, 새로운 스레드를 매번 만들면 비효율적이므로 "스레드 캐시"에서 대기 중인 스레드를 재사용할 수도 있음.

3) 포그라운드 스레드가 SQL을 처리

  • 포그라운드 스레드는 데이터를 가져오거나 저장하는 작업을 수행함.
  • 스토리지 엔진(주방)에서 데이터를 가져올 때, 빠른 처리를 위해 버퍼와 캐시를 사용함.
    • 버퍼(Buffer): 데이터를 처리하기 전에 임시로 저장하는 공간 (육수 준비)
    • 캐시(Cache): 자주 사용하는 데이터를 저장해 빠르게 제공하는 공간 (미리 만들어둔 김치찌개)

4) 결과를 클라이언트에게 반환 후, 스레드 종료 or 재사용

  • SQL 실행 결과를 사용자에게 반환한 후, 포그라운드 스레드는 다시 사용 가능한 상태로 변경됨.
  • 만약 thread_cache_size가 설정되어 있다면, 스레드를 완전히 종료하지 않고 캐시에 보관하여 재사용함.
더보기

 

개념 관리하는 위치 설명
스레드 캐시(Thread Cache) MySQL 엔진 (SQL Layer) - 클라이언트 요청을 빠르게 처리하기 위해 스레드를 캐시함
- 스레드 관리를 위해 사용됨
버퍼(Buffer) MySQL 엔진 (SQL Layer) 데이터를 읽거나 쓰기 전에 임시로 저장하는 공간
(ex. InnoDB Buffer Pool)
캐시(Cache) MySQL 엔진 (SQL Layer) 자주 사용하는 데이터를 저장해 빠르게 제공
(ex. InnoDB Adaptive Hash Index)

 

  • 스레드 캐시는 MySQL 엔진에서 스레드 관리를 위해 사용됨.
  • 버퍼와 캐시도 MySQL 엔진에서 관리하며, 특히 스토리지 엔진(InnoDB, MyISAM 등)이 이를 활용하는 구조

 

 
 

2️⃣ 백그라운드 스레드

MySQL 서버의 안정적인 운영을 위해 내부적으로 실행되는 스레드

 

인서트 버퍼를 병합하는 스레드Purge 스레드인서트 버퍼(Insert Buffer) 최적화 수행.
InnoDB에서 보조 인덱스를 효율적으로 관리하기 위해 인서트 버퍼 병합
로그를 디스크로 기록하는 스레드Redo Log Writer 스레드InnoDB의 Redo Log를 디스크에 기록하여 데이터 무결성을 보장.
장애 발생 시 복구를 위해 필요한 정보 저장
InnoDB 버퍼풀의 데이터를
디스크에 기록하는 스레드
Checkpointer 스레드버퍼 풀(Buffer Pool)의 변경된 데이터를 디스크에 저장 (CheckPoint 처리).
메모리에서 사라지기 전에 데이터를 안전하게 저장
데이터를 버퍼로 읽어오는 스레드I/O 스레드디스크에서 데이터를 읽어와 InnoDB 버퍼 풀에 로드.
InnoDB는 성능을 높이기 위해 다중 I/O 스레드를 사용
잠금이나 데드락을 모니터링하는 스레드InnoDB 관리 스레드잠금(Lock) 상태 및 데드락(Deadlock) 감지 후 해결

 

 

더보기

📌 로그 관련 스레드 (Redo Log Writer & Checkpointer)

1️⃣ Redo Log Writer 스레드 (로그를 디스크에 기록하는 스레드)

역할:

  • **InnoDB의 Redo 로그(복구용 로그)**를 디스크에 기록하는 역할
  • Redo 로그는 트랜잭션이 커밋되기 전에 먼저 기록되어야 함 → 크래시 복구(crash recovery) 시 데이터 무결성 보장

작동 방식:

  1. 사용자가 INSERT, UPDATE, DELETE 쿼리를 실행
  2. InnoDB가 변경된 데이터를 **버퍼 풀(Buffer Pool)**에 먼저 저장
  3. 동시에 Redo Log Writer가 변경 내용을 로그 파일(redo log)에 기록
  4. 데이터가 디스크로 완전히 기록되지 않았더라도, Redo 로그를 사용하면 트랜잭션 복구 가능

왜 중요한가?

  • 디스크 I/O를 줄이기 위해 데이터를 바로 디스크에 쓰지 않고, 로그를 먼저 기록
  • MySQL이 비정상 종료되더라도 Redo 로그를 사용하여 변경된 데이터를 복구

2️⃣ Checkpointer 스레드 (버퍼 풀의 데이터를 디스크에 기록하는 스레드)

역할:

  • InnoDB 버퍼 풀(Buffer Pool)의 변경된 데이터를 디스크로 기록
  • 체크포인트(CheckPoint) 생성: 특정 시점에서 변경된 데이터를 모두 디스크에 반영하여 데이터 일관성을 유지

작동 방식:

  1. 버퍼 풀에 있는 데이터는 메모리에 캐싱되어 빠르게 접근 가능
  2. 하지만 메모리는 휘발성이므로, 일정 시간마다 버퍼 풀에서 변경된 데이터를 디스크로 기록
  3. 이 작업을 수행하는 게 Checkpointer 스레드
  4. Checkpoint를 기록하면, 그 시점 이전의 Redo 로그는 더 이상 필요 없으므로 삭제 가능

왜 중요한가?

  • Checkpoint를 사용하면 불필요한 Redo 로그를 삭제하여 성능 최적화
  • 서버가 갑자기 종료되더라도, 가장 최근 Checkpoint 이후의 Redo 로그만 사용하여 빠르게 복구 가능 



4.1.3 메모리 할당 및 사용 구조


 
MySQL 서버 내에 존재하는 스레드가 공유해서 사용하는 공간인지 여부에 따라
"글로벌 메모리 영역" "세션 메모리 영역"으로 구분한다.
 
 
 

1️⃣ 글로벌 메모리 영역

  • 서버 전체에서 공유하는 메모리 공간
  • 모든 스레드(클라이언트 요청)에서 함께 사용
  • MySQL의 시스템 변수로 설정해 둔 만큼 운영체제로부터 메모리를 할당받음
  • 모든 클라이언트(스레드)가 공유하는 메모리이므로 크기 설정이 중요함

 

2️⃣ 로컬 메모리 영역

  • 각각의 클라이언트 스레드가 개별적으로 사용하는 메모리 공간
  • 클라이언트(사용자)가 쿼리를 실행할 때 동적으로 할당됨
  • 쿼리 실행이 끝나면 자동으로 해제됨

 
 

 
 

4.1.6 쿼리 실행 구조


 
 

1️⃣ 쿼리 파서

  • 사용자 요청으로 들어온 쿼리 문장을 토큰(MySQL이 인식할 수 있는 최소 단위의 어휘나 기호)으로 분리해 트리 형태의 구조로 만들어 내는 작업
  • 쿼리 문장의 기본 문법 오류가 발견되는 단계
  • 사용자에게 오류 메시지 전달

 

2️⃣ 전처리기

  • 파서 과정에서 만들어진 파서 트리를 기반으로 쿼리 문장에 구조적인 문제점이 있는지 확인
  • 토큰을 매핑하여 객체의 존재 여부, 객체의 접근 권한 등을 확인하는 과정
  • 실제 존재하지 않거나, 권한상 사용할 수 없는 개체의 토큰이 걸러지는 단계

 

3️⃣ 옵티마이저

  • 사용자의 요청으로 들어온 쿼리 문장을 저렴한 비용으로 가장 빠르게 처리할지를 결정하는 역할 담당
  • 경영진 포지션에 해당. DBMS의 두뇌

 

4️⃣ 실행 엔진

  • 만들어진 계획대로 각 핸들러에게 요청해서 받은 결과를 또 다른 핸들러 요청의 입력으로 연결하는 역할
  • ex1 ) 핸들러에게 임시 테이블을 만들라고 요청, 조건과 일치하는 레코드를 읽어오라 요청 ..
  • ex2 ) 최종 결과를 사용자나 다른 모듈로 넘김 

 

5️⃣ 핸들러(스토리지 엔진) 

  • MySQL 서버의 가장 밑단에 위치. 핸들러와 스토리지 엔진을 동일 의미로 이해 
  • MySQL 실행 엔진의 요청에 따라 데이터를 디스크로 저장하고, 디스크로부터 읽어 오는 역할 담당
  • ex ) MyISAM 스토리지 엔진 (MyISAM 테이블을 조작하는 핸들러), InnoDB 스토리지 엔진 (InnoDB 테이블 조작하는 핸들러)

 
 
 

4.1.7 쿼리 캐시


 
MySQL 8.0으로 올라오면서 쿼리 캐시는 MySQL 서버의 기능에서 완전히 제거됨 (관련 시스템 변수 모두)
 
 
 

4.1.8 스레드 풀


 

  • MySQL에서 요청을 처리하는 스레드 개수를 제한하여 CPU가 효율적으로 동작하도록 설계된 기능
  • CPU 코어 개수만큼 스레드 그룹을 생성하고, 각 그룹당 제한된 개수의 스레드만 실행하여 불필요한 스레드 생성을 방지
  • 기본 MySQL에는 없고, Percona Server나 MariaDB 등에서 제공하는 기능

 
1) CPU 코어 개수만큼 스레드 그룹(Thread Group) 생성

  • 예를 들어, 4코어 CPU라면 4개의 스레드 그룹을 생성.
  • 각 스레드 그룹은 CPU 코어 하나를 담당.

2) 각 스레드 그룹 내에서 제한된 개수의 스레드만 실행

  • 일반적으로 MySQL은 요청이 올 때마다 새로운 스레드를 생성.
  • 스레드 풀은 특정 개수만큼만 스레드를 실행하여 불필요한 스레드 생성을 막음.
  • 예를 들어, 각 그룹당 5개 스레드라면, 총 20개의 스레드만 실행됨 (4코어 × 5개).

3) 스케줄링을 통해 요청을 적절히 분배

  • 요청이 많아질 경우, 선순위 / 후순위 큐로 정렬하여 우선 처리할 요청을 결정.
  • 특정 요청이 너무 오래 대기하지 않도록, 스케줄러가 적절한 순서로 요청을 배정.

4) MySQL 서버가 CPU를 최적화하여 사용

  • 불필요한 스레드 생성이 없으므로, CPU 리소스 낭비를 줄임.
  • 특정 스레드가 과부하 걸리지 않도록 분산 처리하여 성능을 유지함.

 
 
 
 
 

4.2 InnoDB 스토리지 엔진 아키텍처 

 

  • 스토리지 엔진 중 거의 유일하게 레코드 기반의 잠금 제공
  • 높은 동시성 처리 가능, 안정적이며 성능이 뛰어남

책에서 설명하는 InnoDB 스토리지 엔진의 특징은 아래 6가지이다. (4.2.1 ~ 4.2.6)
 
 
 

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


🌟 클러스터링(Clustering)
: 데이터가 특정 기준(예: 프라이머리 키)에 따라 정렬되어 디스크에 저장되는 방식

🌟 클러스터링 인덱스(Clustered Index)
: 테이블의 실제 데이터가 특정 인덱스 순서에 맞춰 정렬되어 저장되는 구조.

 

  • 프라이머리 키 값 자체가 데이터의 위치를 결정 → 프라이머리 키 변경 시 데이터의 물리적 위치가 바뀔 수 있음
  • 세컨더리 인덱스(Secondary Index)는 프라이머리 키 값을 저장하여 검색에 활용
특징 InnoDB MyISAM
클러스터링✅ 프라이머리 키 기반 클러스터링
(데이터가 PK 순서대로 저장)
❌ 클러스터링 없음 (데이터와 인덱스가 별도로 저장)
세컨더리 인덱스 ✅ 세컨더리 인덱스가 프라이머리 키를 참조 ❌ 세컨더리 인덱스가 직접 데이터 위치를 저장
트랜잭션 지원 ✅ ACID 보장, 트랜잭션 지원 ❌ 트랜잭션 미지원
외래 키
(Foreign Key) 지원
✅ 지원 ❌ 미지원

 
 
 

4.2.2 외래 키 지원


🌟 외래 키 (Foreign Key)
: 하나의 테이블에서 다른 테이블의 특정 열을 참조하는 방식. 두 테이블 간의 관계를 정의
: 데이터 무결성을 보장하기 위해 사용

🌟 트랜잭션
: 데이터베이스에서 하나의 논리적인 작업 단위. 하나라도 실패하면 전체 작업을 취소해야 함
: 묶어서 처리하는 작업 단위
 트랜잭션 예시 (은행 송금)  "A가 B에게 10만 원을 송금"
1) A 계좌에서 10만 원 차감
2) B 계좌에 10만 원 추가

🌟 데드락
: 두 개 이상의 트랜잭션이 서로가 잠근 리소스를 기다리고 있어, 결국 아무 것도 진행되지 않는 상황

데드락 발생 예시
1) 트랜잭션 A: 부모 테이블의 행을 잠그고 자식 테이블을 수정하려고 기다린다.
2) 트랜잭션 B: 자식 테이블의 행을 잠그고 부모 테이블을 수정하려고 기다린다.
3) 이 경우 트랜잭션 A트랜잭션 B는 서로가 잠근 리소스를 기다리고 있기 때문에 데드락에 빠지게 된다.

 
InnoDB에서는 외래 키를 사용하는 동시에 여러 트랜잭션이 데이터를 처리할 때 데이터 무결성을 보장하기 위해 잠금을 사용한다.
외래 키가 있는 테이블에서 업데이트나 삭제 작업을 할 때, 부모 테이블과 자식 테이블에 대한 레코드 단위 잠금이 걸리는데,
이 잠금은 데이터의 일관성을 유지하고, 동시에 여러 사용자가 데이터를 처리할 때 문제가 발생하지 않도록 도와준다.
 
잠금으로 인해 데드락이 발생하는데, 이러한 문제를 해결하기 위해서 InnoDB는 아래와 같은 해결 방법을 사용한다.
 

foreign_key_checks 시스템 변수 OFF 설정 : 외래 키 관계에 대한 체크 작업 일시적 멈춤
SET foreign_key_checks=OFF;

// 작업 실행

SET foreign_key_checks=ON;

 
 

4.2.3 MVCC(Multi Version Concurrency Control)


 
MVCC (Multi-Version Concurrency Control)는 데이터베이스에서 다중 사용자가 동시에 데이터를 읽고 쓸 수 있으면서,
일관성 있는 데이터를 유지할 수 있게 하는 동시성 제어 기법이다.
 
InnoDB와 같은 스토리지 엔진에서는 이 기법을 사용하여 트랜잭션 간의 충돌을 최소화하고,
동시에 여러 트랜잭션이 데이터에 접근할 수 있게 한다.
 
각 트랜잭션은 서로의 변경 사항보지 않도록 하는 대신, 각 트랜잭션은 자신만의 데이터 버전을 사용하고,
트랜잭션이 끝난 후에만 데이터가 커밋되어 다른 트랜잭션과 공유된다.
 

 
 
언두 로그 (Undo Log)MVCC의 동작을 지원하는 핵심 요소로,
트랜잭션이 변경한 데이터를 롤백하거나, 일관성을 유지하기 위해 필요한 데이터를 기록하는 역할을 한다.
 
 
 

4.2.4 잠금 없는 일관된 읽기(Non-Locking Consistent Read)


 
MVCC 기술을 이용해 잠금을 걸지않고 읽기 작업을 수행하기 때문에,

격리수준이 SERIALIZABLE이 아닌 경우
INSERT와 연결되지 않은 SELECT 작업은 다른 트랜잭션의 변경 작업과 관계없이 항상 잠금을 대기하지 않고 바로 실행된다.
 
 

4.2.5 자동 데드락 감지


 
내부적으로 잠금이 교착 상태에 빠지지 않았는지 체크하기 위해 잠금 대기 목록을 그래프(Wait-for list) 형태로 관리한다.
데드락 감지 스레드가 주기적으로 검사해 교착 상태에 빠진 트랜잭션을 찾아서 그 중 하나를 종료한다.
 
이때 강제 종료 순서는 트랜잭션의 언두 로그 양이며, 언두 로그 레코드를 더 적게 가진 트랜젝션이 일반적으로 롤백의 대상이 된다.
 
 
 

4.2.6 자동화된 장애 복구


 
InnoDB 데이터 파일은 기본적으로 MySQL 서버가 시작될 때 항상 자동 복구를 수행한다.
서버 설정 파일에 innodb_force_recovery 시스템 변수를 설정하여 파일의 손상 여부 검사를 선별적으로 진행할 수 있게 한다.
 

  • 1(SRV_FORCE_RECOVERY) 
  • 2(SRV_FORCE_NO_BACKGROUND) 
  • 3(SRV_FORCE_NO_TRX_UNDO)
  • 4(SRV_FORCE_NO_IBUF_MERGE)
  • 5(SRV_FORCE_NO_UNDO_LOG_SCAN) 
  • 6(SRV_FORCE_NO_LOG_REDO) 

 

4.2.7 InnoDB 버퍼 풀


 

InnoDB 스토리지 엔진에서 가장 핵심적인 부분으로, 디스크의 데이터 파일이나 인덱스 정보메모리에 캐시해 두는 공간이다.
즉, 디스크에서 직접 데이터를 읽는 게 아닌, 한 번 읽은 데이터를 메모리에 저장해 두고 필요할 때 빠르게 가져오는 역할을 한다.
 
또한 쓰기 작업을 지연시켜 일괄 작업으로 처리할 수 있게 해주는 버퍼 역할도 같이 한다.
이는 변경된 데이터를 모아서 처리하여 랜덤한 디스크 작업의 횟수를 줄인다.
 


1️⃣ 버퍼 풀의 크기 설정

 
운영체제와 각 클라이언트 스레드가 사용할 메모리를 충분히 고려하여 크기를 설정해야 한다.
아주 독특한 경우 레코드 버퍼 가 상당한 메모리를 사용하기에, 적절히 작은 값으로 버퍼 풀의 크기를 설정해서 추후 증가시켜야 한다.
이미 MySQL 서버를 사용하고 있다면 그 서버의 메모리 설정을 기준으로 InnoDB 버퍼 풀의 크기를 조정하면 된다.

더보기

** 레코드 버퍼

각 클라이언트 세션에서 테이블의 레코드를 읽고 쓸 때 버퍼로 사용하는 공간

innodb_buffer_pool_size 시스템 변수로 크기를 설정할 수 있으며, 동적으로 버퍼풀의 크기를 확장할 수 있다.
버퍼 풀의 크기를 줄이는 작업은 서비스 영향도가 매우 크므로 가능하면 버퍼 풀의 크기를 줄이는 작업은 하지 않도록 해야한다.

 
 
 
2️⃣ 버퍼 풀의 구조

 
버퍼 풀은 크게 3가지 주요 영역으로 나뉘어 있다.

구성 요소설명
LRU 리스트 (Least Recently Used List) 자주 사용되는 데이터가 저장됨 (오래된 데이터는 밀려남)
디스크로부터 한 번 읽어온 페이지를 최대한 오래 메모리에 유지하여 디스크 읽기 최소화
플러시 리스트 (Flush List) 변경되었지만 아직 디스크에 반영되지 않은 페이지 목록
프리 리스트 (Free List) 실제 사용자 데이터로 채워지지 않은 아직 사용되지 않은 빈 페이지 목록
사용자의 쿼리가 새롭게 디스크의 데이터 페이지를 읽어와야 하는 경우 사용됨

 

 
InnoDB 스토리지 엔진에서 LRU 리스트 구조가 데이터를 찾는 과정은 다음과 같다.

  1. 필요한 레코드가 저장된 데이터 페이지가 버퍼 풀에 있는지 검사
    • InnoDB 어댑티브 해시 인덱스를 이용해 페이지를 검색
    • 해당 테이블의 인덱스(B-Tree)를 이용해 버퍼 풀에서 페이지 검색
    • 버퍼 풀에 이미 데이터 페이지가 있다면 해당 페이지 포인터를 MRU 방향으로 승급
  2. 디스크에서 필요한 데이터 페이지를 버퍼 풀에 적재, 적재된 페이지에 대한 포인터를 LRU 헤더 부분에 추가
  3. 버퍼 풀의 LRU 헤더 부분에 적재된 데이터 페이지가 실제로 읽히면 MRU 헤더부분으로 이동
  4. 버퍼 풀에 상주하는 데이터 페이지는 사용자 쿼리가 얼마나 최근에 접근했는지에 따라 나이Age가 부여되며, 오랫동안 사용되지 않으면 버퍼 풀에서 제거
  5. 필요한 데이터가 자주 접근됐다면 해당 페이지의 인덱스 키를 어댑티브 해시 인덱스에 추가

 

 
 
 
 

3️⃣ 버퍼 풀과 리두 로그

Redo Log는 복구를 위한 것. 변경 후 데이터(New Data) 저장하고 복구

 
리두 로그( Redo Log )는 InnoDB 스토리지 엔진에서 변경된 데이터를 디스크에 반영하기 전에 먼저 기록하는 로그 시스템을 말한다.
데이터 변경 과정에서 트랜잭션이 COMMIT되면 리두 로그에 기록된 후, 일정 시점에 디스크에 반영된다.
이를 통해 장애 발생 시 복구 가능하며, 체크포인트(Checkpoint)에서 더티 페이지를 디스크에 반영하여 데이터 일관성 유지한다.

1) 데이터 조회 → 클린 페이지 (Clean Page)
2) 데이터 변경 → 더티 페이지 (Dirty Page) 생성, 리두 로그 기록
3) 트랜잭션 COMMIT → 리두 로그 디스크에 저장
4) 체크포인트 발생 → 더티 페이지를 LSN 순서대로 디스크에 반영 → 클린 페이지로 변경 -> 리두 로그 공간 확보

 

더보기

** Redo Log의 주요 개념 **

① LSN (Log Sequence Number, 로그 순서 번호)

  • MySQL에서 각 트랜잭션의 변경 내용을 고유하게 식별하기 위한 번호
  • 새로운 변경이 발생할 때마다 증가
  • LSN을 사용하면 "어떤 변경이 언제 발생했는지"를 순서대로 추적 가능

② 리두 로그 엔트리 (Redo Log Entry)

  • 트랜잭션의 변경 내용(UPDATE, INSERT, DELETE 등)이 기록된 단위
  • 예를 들어, UPDATE users SET age = 30 WHERE id = 1; 실행 시:
    • "테이블 users의 id=1인 row의 age 값을 30으로 변경" 이라는 정보가 Redo Log Entry로 기록됨
  • 이 정보는 디스크에 기록되기 전에도 InnoDB가 복구할 수 있도록 보장

③ 체크포인트 (Checkpoint)

  • Redo Log가 너무 커지지 않도록, 특정 시점에서 변경 내용을 실제 데이터 파일에 반영하는 과정
  • 체크포인트가 발생하면 이전의 리두 로그는 더 이상 필요 없으므로 삭제 가능
  • 즉, 체크포인트 이전의 데이터는 이미 디스크에 안전하게 반영된 상태

④ 체크포인트 에이지 (Checkpoint Age)

  • 현재 LSN - 체크포인트의 LSN 차이
  • 쉽게 말해 "디스크에 반영되지 않고 Redo Log에만 저장된 변경 내역의 크기"
  • 체크포인트 에이지가 너무 크면, 복구할 때 시간이 오래 걸릴 수 있음
더보기

** 데이터 변경 시 처리 과정 ** 

1) SELECT 실행 (읽기)

📌 버퍼 풀에서 데이터 조회 (클린 페이지 활용)
클라이언트가 데이터를 조회하면, InnoDB는 버퍼 풀(Buffer Pool) 에 해당 페이지가 있는지 확인
* 있으면 → 바로 반환 (캐싱 효과)
* 없으면 → 디스크에서 읽어와 버퍼 풀에 적재 후 반환
이때 읽어온 페이지는 클린 페이지 (Clean Page) 상태

2) INSERT / UPDATE / DELETE 실행 (쓰기)

📌 버퍼 풀의 데이터를 변경하여 더티 페이지(Dirty Page) 생성
사용자가 데이터를 변경하면, InnoDB는 버퍼 풀에서 해당 데이터를 수정
수정된 페이지는 더티 페이지 (Dirty Page) 가 됨 (변경된 데이터가 아직 디스크에 저장되지 않은 상태)
변경 내용은 즉시 디스크에 반영되지 않고, 리두 로그(Redo Log)에 먼저 기록

📌 리두 로그(Redo Log) 기록
InnoDB는 변경된 데이터를 먼저 리두 로그에 기록 (COMMIT 전에 디스크 반영 X)
트랜잭션이 COMMIT 되면, 변경 사항이 디스크로 안전하게 저장되었다고 보장됨
➡ 즉, 데이터 변경 시 "버퍼 풀 → 리두 로그 → 디스크 반영(체크포인트 시점)" 순으로 처리

3) COMMIT 후 리두 로그 플러시 (트랜잭션 안전성 보장)

📌 리두 로그를 디스크에 기록하여 장애 복구 대비

  • 트랜잭션이 COMMIT 되면, InnoDB는 리두 로그를 디스크로 플러시(fsync)하여 저장
  • 이후, 일정 시점(체크포인트)에서 더티 페이지를 디스크에 반영

🚨 만약 MySQL이 장애로 종료되면?

  1. 디스크에 저장되지 않은 더티 페이지가 남아있어도 리두 로그에 변경 사항이 남아 있음
  2. 리두 로그를 통해 변경 내용을 다시 적용(복구)하여 데이터 무결성을 유지

4 ) 체크포인트 발생 (더티 페이지 -> 디스크 저장)
📌 체크포인트(Checkpoint)에서 더티 페이지를 디스크로 반영

  • 일정 주기마다 InnoDB는 더티 페이지를 디스크에 저장
  • 더티 페이지가 디스크에 반영되면 다시 클린 페이지가 됨

 체크포인트 과정 덕분에, InnoDB는 변경 사항을 디스크에 한꺼번에 저장하여 디스크 I/O 부담을 줄임

 

4️⃣ 버퍼 풀 플러시(Buffer Pool Flush)

 
버퍼 풀 플러시는 InnoDB 버퍼 풀에 있는 변경된 데이터(더티 페이지)를 디스크에 기록하는 과정이다.
앞서 4.2.7.3에서 살펴보았던 리두 로그 내용에서 아래 부분에 해당되는 내용이 버퍼 풀 플러시이다.

4) 체크포인트 발생 → 더티 페이지를 LSN 순서대로 디스크에 반영 → 클린 페이지로 변경 -> 리두 로그 공간 확보


디스크 쓰기 성능을 최적화하고, 크래시 복구를 원활하게 하기 위해 InnoDB는 여러 가지 방식으로 플러시를 수행한다.
 

플러시 리스트 플러시

 
개념

  • 변경된 페이지(더티 페이지)를 Redo Log의 로그 시점(LSN) 순서대로 기록
  • 체크포인트(Checkpoint) 작업과 밀접한 관련이 있음

동작 방식

  1. 트랜잭션이 데이터를 변경하면, 해당 페이지는 더티 페이지가 되어 Flush List에 추가됨
  2. 체크포인트가 도달하거나, Redo Log 공간이 부족해지면 Flush List의 더티 페이지가 디스크에 기록됨
  3. 플러시 후, 더티 페이지가 클린 페이지로 변경됨

특징

  • Redo Log를 정리하는 역할
  • 트랜잭션의 영속성을 보장
  • 백그라운드에서 주기적으로 수행됨

 

LRU 리스트 플러시

 
개념

  • 버퍼 풀이 가득 차서 새로운 페이지를 로드할 공간이 없을 때 실행됨
  • 자주 사용되지 않은 페이지(Least Recently Used)를 디스크에 기록하여 공간 확보

동작 방식

  1. 새로운 데이터 페이지가 로드되면, 버퍼 풀의 빈 공간이 필요
  2. LRU 리스트에서 오랫동안 사용되지 않은 페이지를 선택하여 디스크에 기록(플러시)
  3. 플러시된 페이지는 버퍼 풀에서 제거되고, 새 페이지가 로드됨

특징

  • 버퍼 풀 공간 확보를 위한 플러시 방식
  • 오래 사용되지 않은 페이지부터 제거 (LRU 정책 활용)
  • 읽기 성능을 최적화하는 역할

 
 

5️⃣ 버퍼 풀 상태 백업 및 복구
 

MySQL 서버 셧다운 전에 버퍼 풀의 상태 백업

SET GLOBAL innodb_buffer_pool_dump_now = ON;

 
MySQL 서버 재시작 후, 백업된 버퍼 풀의 상태 복구

SET GLOBAL innodb_buffer_pool_load_now = ON;

 


6️⃣ 버퍼 풀의 적재 내용 확인

 
information_schema 데이터베이스에 innodb_cached_indexes 테이블 추가

SELECT
    it.name table_name,
    ii.name index_name,
    ici.n_cached_pages n_cached_pages
FROM information_schema.innodb_tables it
    INNER JOIN information_schema.innodb_indexs ii ON ii.table_id = it.table_id
    INNER JOIN information_schema.innodb_cached_indexes ici ON ici.index_id = ii.index_id
WHERE it.name=CONCAT('employees','/','employees');


 
 
 

4.2.8 Double Write Buffer


 
 하드웨어의 오작동이나 시스템의 비정상 종료 등으로
스토리지 엔진에서 더티 페이지를 디스크 파일로 플러시할 때 일부만 기록되는 문제가 발생할 수 있다.

이러한 현상을 파셜 페이지(Partial-page) 또는 톤 페이지(Torn-page) 현상이라고 부르는데,
InnnoDB 스토리지 엔진에서 이 해결 방법으로 사용되는 기법이 Double-Write 기법이다.
 



 
 

4.2.9 언두 로그

Undo Log는 롤백을 위한 것. 변경 전 데이터(Old Data) 저장

 
앞서 4.2.3에서 언두 로그란 MVCC의 동작을 지원하는 핵심 요소로,
트랜잭션이 변경한 데이터를 롤백하거나, 일관성을 유지하기 위해 필요한 데이터를 기록하는 역할을 한다고 살펴봤다.
 
즉, 언두 로그는
트랜잭션과 격리 수준을 보장하기 위해 DML로 변경되기 이전 버전의 데이터를 별도로 백업하는 데이터를 의미하는데,
이 언두 로그의 문제점을 해결하기 위해 InnoDB 스토리지 엔진은 아래와 같은 기능을 제공한다.
 
 

1️⃣ 언두 로그 레코드 모니터링

 
대용량의 데이터를 처리하는 트랜잭션뿐만 아니라 트랜잭션이 오랜 시간 동안 실행될 때에는 언두 로그 양이 급격히 증가한다.
 
예를 들어 트랜잭션1,2가 완료가 되었지만, 나머지 트랜잭션3이 아직 활성 상태일 때는, 
트랜잭션1,2 완료 여부와 관계없이 1,2 트랜잭션이 만들어낸 언두 로그는 삭제되지 않는다.
빈번하게 변경된 레코드를 조회하는 쿼리가 실행되면 InnoDB 스토리지 엔진은 언두 로그의 이력을 필요한 만큼 스캔해야만 피료한 레코드를 찾을 수 있기 때문에 쿼리의 성능이 전반적으로 떨어지게 된다.
 
MySQL 8.0에서는 언두 로그를 돌아가면서 순차적으로 사용해 디스크 공간을 줄이는 것을 가능하게 했으며,
MySQL 서버가 필요한 시점에 사용 공간을 자동적으로 줄여 주는 기능을 제공하게 되었다.
 
그리고 서비스 중인 MySQL 서버에서 활성 상태의 트랜잭션이 장시간 유지되는 것은 성능상 좋지 않기 때문에,
MySQL 서버의 언두 로그 레코드가 얼마나 되는지 항상 모니터링하는 것이 좋다.

SHOW ENGINE INNODB STATUS \G


 

2️⃣ 언두 테이블스페이스 관리

 
언두 테이블스페이스는 언두 로그가 저장되는 공간을 의미한다.
MySQL 8.0으로 업그레이드 되면서 inndo_undo_tablespaces 시스템 변수의 효과는 없어졌으며,
언두 로그는 항상 시스템 테이블스페이스 외부의 별도 로그 파일에 기록되도록 개선됐다.
 
 그리고 MySQL 8.0 버전부터는 새로운 언두 테이블 스페이스를
CREATE UNDO TABLESPACE나 DROP TABLESPACE 명령어를 통해 동적으로 추가하고 삭제할 수 있게 개선되었다.
 
 
 
 

4.2.10 체인지 버퍼


 
InnoDB는 변경해야 할 인덱스 페이지가 버퍼 풀에 있으면 바로 업테이트를 수행하지만,
그렇지 않고 디스크로부터 읽어와서 업데이트해야 한다면 이를 바로 실행시키지 않는다. 
 
 체인지 버퍼라고 부르는 임시 메모리 공간에 해당 정보를 저장해 두고 바로 사용자에게 결과를 반환하는 형태로 성능향상을 한다.
 

 

4.2.11 리두 로그 및 로그 버퍼


 

1️⃣ 리두 로그 아카이빙

🌟아카이빙(Archiving)
: 리두 로그가 덮어씌워지기 전에 저장해 두는 작업

 
MySQL 8.0의 리두 로그 아카이빙 기능은 데이터 변경이 많아서 리두 로그가 덮어쓰인다고 하더라도 백업이 실패하지 않게 해준다.
 
1. MySQL 서버에서 아카이빙된 리두 로그가 저장될 디렉토리를 innodb_redo_log_archive_dirs 시스템 변수에 설정
2. innodb_redo_log_archive_start UDF 실행
3. 종료할 때는 innodb_redo_log_archive_stop UDF 실행
 
 


2️⃣ 리두 로그 활성화 및 비활성화

ALTER INSTANCE DISABLE INNODB REDO_LOG;  // 비활성화
ALTER INSTANCE ENABLE INNDO REDO_LOG;    // 활성화


 리두 로그 비활성화하고 데이터 적재 작업을 실행했다면 데이터 적재 완료 후 리두 로그를 다시 활성화 해야한다.
 
 
 

4.2.12 어댑티브 해시 인덱스


 
 InnoDB에서 어댑티브 해시 인덱스는 사용자가 자주 요청하는 데이터에 대해 자동으로 생성하는 인덱스를 의미한다.
 innodb_adaptive_hash_index 시스템 변수를 이용해서 해당 기능을 활성화할 수 있다.

SET GLOBAL innodb_adaptive_hash_index = ON;

 
B-Tree 인덱스 검색 시간을 줄여주기 위해 도입된 기능이며,
필요할 때마다 어댑티브 해시 인덱스를 검색해서 레코드가 저장된 데이터 페이지를 즉시 찾아갈 수 있다

더보기

** B-Tree 인덱스

 
이는 비용의 감소뿐만 아니라 CPU가 적은 일을 하게 하며, 쿼리의 성능은 빨라진다.
더 많은 쿼리를 동시에 처리할 수 있게 된다는 뜻이다.
 
 
간혹 어댑티브 해시 인덱스를 의도적으로 비활성화하는 경우도 있다.
성능 향상에 크게 도움이 되지 않을 때는 아래와 같으며

  • 디스크 읽기가 많은 경우
  • 특정 패턴의 쿼리가 많은 경우(조인이나 LIKE 패턴 검색)
  • 매우 큰 데이터를 가진 테이블의 레코드를 폭넓게 읽는 경우

성능 향상에 크게 도움이 되는 경우는 아래와 같다.

  • 디스크의 데이터가 InnoDB 버퍼 풀 크기와 비슷한 경우(디스크 읽기가 많지 않은 경우)
  • 동등 조건 검색(동등 비교와 IN 연산자)이 많은 경우
  • 쿼리가 데이터 중 일부 데이터에만 집중되는 경우


 
 
 

4.3 MyISAM 스토리지 엔진 아키텍처 

 

4.3.1 키 캐시


 
MyISAM의 키 캐시는 MyISAM 테이블의 인덱스를 메모리에 캐싱하는 기능을 한다.(데이터 파일은 캐싱 x)
 
 
즉 디스크에서 반복적으로 인덱스를 읽는 비용을 줄이고, 인덱스 조회 성능을 향상시키는 역할을 하고,
MyISAM은 데이터와 인덱스를 분리해서 저장하므로, 인덱스 읽기 속도를 높이기 위해 키 캐시를 활용한다.
 

** 키 캐시 작동 방식 **

1. 클라이언트가 MyISAM 테이블의 인덱스를 조회
2. 키 캐시(Key Cache)가 해당 인덱스를 메모리에 보관
3. 이후 동일한 인덱스를 조회하면, 디스크가 아니라 키 캐시에서 바로 가져옴
4. 디스크 I/O를 줄여 성능을 향상

 
뿐만 아니라 MyISAM의 키 캐시는  인덱스의 디스크 쓰기 작업에 대해서만 부분적으로 버퍼링 역할을 한다. 
 
 

키 캐시 관련 설정

키 캐시 히트율 (Hit rate) = 100 - ( Key_reads / Key_read_requests * 100)
  • 매뉴얼에서는 키 캐시를 이용한 쿼리의 비율을 99% 이상으로 유지하라고 권장
  • Key_read_requests: 캐시에 저장된 인덱스를 읽은 요청 수
  • Key_reads: 캐시에 없는 인덱스를 디스크에서 읽은 횟수
  • "Key_reads / Key_read_requests" 비율이 낮을수록 캐시 효율이 좋음

 

key_buffer_size
  • 기본(Default) 키 캐시 공간을 설정하는 파라미터 -> 32비트 운영체제에서는 4GB 이상의 메모리 공간 설정 x
  • 제한 값 이상의 키 캐시를 할당하고 싶다면 별도의 명명된 키 캐시 공간을 설정 + 캐시할 인덱스 정보 설정해야 함
1. 키 캐시 공간 설정
key_buffer_size = 4GB  // Default

kbuf_board.key_buffer_size = 2GB     // kbuf_board 키 캐시 공간 설정
kbuf_comment.key_buffer_size = 2GB   // kbuf_comment 키 캐시 공간 설정

2. 인덱스가 캐시되도록 설정
CACHE INDEX db1.board, db2.board IN kbuf_board;         // board 테이블의 인덱스가 kbuf_board 캐시 사용
CACHE INDEX db1.comment, db2.comment IN kbuf_comment;   // comment 테이블의 인덱스가 kbuf_comment 캐시 사용
더보기

📌 키 캐시를 언제 활용하면 좋을까?

✅ MyISAM 테이블을 사용하는 경우
✅ 읽기 위주의 쿼리가 많은 경우 (예: 검색 엔진, 로그 분석)
✅ 메모리 사용량을 적절히 조절해야 하는 경우 

 
 

4.3.2 운영체제의 캐시 및 버퍼


 
앞서 4.3.1에서 MyISAM의 키 캐시는 InnoDB 버퍼 풀과 달리 테이블의 데이터 파일은 캐싱하지 않는다고 하였다.
그래서 MyISAM 테이블의 데이터 읽기나 쓰기 작업은 항상 운영체제의 디스크 읽기 또는 쓰기 작업으로 요청될 수밖에 없다.
 
운영체제는 디스크 I/O 성능을 최적화하기 위해 캐시(Cache)버퍼(Buffer) 개념을 사용한다.
이것이 MyISAM 테이블의 데이터 파일을 빠르게 읽고 쓰는 데 중요한 역할을 한다.
 
운영체제의 캐시 공간은 남는 메모리를 사용하는 것이 기본 원칙이기에, 충분한 메모리를 비워두어야 한다.
 

더보기

1️⃣ 운영체제의 캐시 (Page Cache)

  • 운영체제가 파일을 읽을 때, RAM에 데이터를 저장하여 이후 같은 요청 시 디스크가 아닌 메모리에서 가져오도록 함
  • MyISAM 테이블의 데이터 파일은 InnoDB처럼 자체적인 캐싱을 하지 않으므로, OS의 캐시(Page Cache)에 의존
  • 즉, MyISAM의 데이터 읽기 성능은 운영체제의 캐시 정책에 영향을 받음
  • 만약 운영체제가 캐시에서 데이터를 제거하면, 다시 디스크에서 읽어야 하므로 성능 저하 가능성

2️⃣ 운영체제의 버퍼 (Write Buffer)

  • 데이터를 즉시 디스크에 기록하는 것이 아니라, 일정량이 모이면 한꺼번에 기록하여 디스크 I/O를 줄이는 기법
  • MyISAM 테이블은 운영체제의 버퍼링 메커니즘을 활용하여 데이터 파일을 기록
  • 하지만 MyISAM 자체적으로 트랜잭션을 지원하지 않으므로, 갑작스러운 장애 발생 시 데이터 유실 위험

 

4.3.3 데이터 파일과 프라이머리 키(인덱스)구조


 
MyISAM 테이블은 InnoDB 스토리지 엔진과 달리 프라이머리 키에 의한 클러스터링 없이 
데이터 파일힙(Heap) 공간처럼 활용된다. ( 프라이머리 키(Primary Key)를 기준으로 클러스터링해서 데이터를 정렬하지 x)

✅ 힙(Heap) 공간처럼 활용된다는 의미
* 새로운 데이터가 들어오면 파일의 빈 공간(가장 먼저 발견된 공간)에 저장
* 특정 레코드가 삭제되면 그 공간이 비어 있다가, 새로운 데이터가 들어올 때 다시 사용됨
* 데이터가 논리적으로 정렬되지 않으므로, 프라이머리 키 기반의 범위 조회가 느릴 수 있음

 

 그리고 MyISAM 테이블에 저장되는 레코드는 모두 ROWID라는 물리적인 주솟값을 가지는데,
MyISAM 테이블에서 ROWID는 가변 길이고정 길이의 두 가지 방법으로 저장될 수 있다.

가변 길이 (Dynamic Format)- 가변 길이 데이터 (VARCHAR, TEXT, BLOB)가 포함된 테이블에 사용됨.
- 각 행의 길이가 다르므로, ROWID가 변경될 수 있음.
- 레코드 삭제 시 공간이 단편화될 가능성이 있음.
고정 길이 (Fixed Format)- 고정 길이 데이터 (CHAR, INT, DECIMAL 등)만 포함된 테이블에 사용됨.
- 모든 레코드의 크기가 동일하여, ROWID가 일정함.
- 삭제된 공간을 새로운 레코드가 재사용하기 쉬움.

 

더보기

** ROWID를 활용한 데이터 조회 방식 **


1. 프라이머리 키 조회

  • MyISAM에서는 프라이머리 키도 일반 인덱스(B-Tree)로 관리되며, ROWID를 통해 데이터 파일에서 실제 레코드 위치를 찾음
  • 따라서 프라이머리 키 조회 속도가 InnoDB보다 느림 (InnoDB는 프라이머리 키가 클러스터링 인덱스 역할을 함)

2. 세컨더리 인덱스 조회

  • 세컨더리 인덱스 역시 ROWID를 저장하고, ROWID를 기반으로 데이터 파일에서 레코드를 검색
  • 이 과정이 추가적인 I/O를 발생시켜 조회 속도를 저하시킬 수 있음


 

4.4 MySQL 로그 파일 

 

4.4.1 에러 로그 파일


 
 

  • MySQL 서버에서 오류(Error), 경고(Warning), 주요 이벤트(Event)를 기록하는 로그 파일
  • 서버가 시작(Start)되거나 종료(Shutdown)될 때, 또는 충돌(Crash) 발생 시 중요한 정보를 기록

 


 

4.4.2 제너럴 쿼리 로그 파일(제너럴 로그 파일, General log)


 

  • MySQL이 수행한 모든 SQL 쿼리를 기록하는 로그 파일
  • 디버깅 또는 문제 발생 시 사용자가 실행한 모든 명령을 추적하는 데 사용됨

 
 
 
 

4.4.3 슬로우 쿼리 로그 


 
 

  • 실행 시간이 지정된 임계값(기본 10초)을 초과한 느린 쿼리를 기록하는 로그 파일
  • 쿼리 최적화 및 성능 개선을 위해 주로 사용됨