본문으로 건너뛰기
김신건의 로그

[DB] MySQL / InnoDB: clustered index, redo log, MVCC

· 수정 · 📖 약 3분 · 861자/단어 #mysql #innodb #database #sql
MySQL, InnoDB, clustered index, secondary index, redo log, undo log, buffer pool, binlog, doublewrite buffer, adaptive hash index

정의

MySQL + InnoDB (기본 스토리지 엔진) 의 clustered index + redo log 기반 행 기반 RDBMS. 웹 / SaaS 의 가장 흔한 backbone.

아키텍처

flowchart TB
    Client --> Server["MySQL Server<br/>(parser, optimizer, query cache)"]
    Server --> InnoDB
    subgraph InnoDB["InnoDB Storage Engine"]
        direction LR
        BP["Buffer Pool<br/>(메모리 캐시)"]
        AHI["Adaptive Hash Index"]
        CL["Change Buffer"]
        RedoLog["Redo Log<br/>(WAL)"]
        UndoLog["Undo Log<br/>(MVCC)"]
        DWB["Doublewrite Buffer"]
        DataFiles[("ibd 데이터 파일")]
        BP --> DWB --> DataFiles
    end
    Server -->|writes| Binlog[("Binlog<br/>replication")]

Clustered Index (vs PostgreSQL)

PostgreSQLMySQL InnoDB
Primary 데이터 저장heap + 별도 인덱스primary key 의 B-tree leaf
Secondary index → 데이터tid (heap 위치)primary key 값
Secondary lookup1 hop2 hop (인덱스 → PK → 데이터)
PK 영향작음 (변경 시 secondary index 도 갱신)
flowchart TB
    subgraph InnoDB
        PK["Primary Key B-tree<br/>leaf = 실제 row 데이터"]
        Sec["Secondary Index B-tree<br/>leaf = PK 값"]
        Sec -->|"PK lookup (2 hop)"| PK
    end

IMPORTANT

InnoDB 의 PK 선택은 결정적. 큰 PK (UUID v4) = 모든 secondary index 가 큰 leaf. AUTO_INCREMENT BIGINT 가 보통 정답.

Redo Log + Undo Log

sequenceDiagram
    Client->>InnoDB: UPDATE ...
    InnoDB->>UndoLog: 옛 값 보관 (MVCC + rollback)
    InnoDB->>BufferPool: page dirty
    InnoDB->>RedoLog: 변경 기록 (WAL)
    InnoDB-->>Client: COMMIT (redo fsync 후)
    Note over InnoDB: Checkpoint 시점에 page → disk
로그역할
Redo Logcrash recovery, WAL
Undo LogMVCC + rollback
Binlogreplication, point-in-time recovery

MySQL 8.0.30+ Redo Log 개선

  • Redo log 는 순환 파일 (기본 2개)동적 크기 로 변경.
  • innodb_redo_log_capacity 단일 파라미터로 제어 (옛 innodb_log_file_size × innodb_log_files_in_group).

Doublewrite Buffer

페이지 손상 (partial write) 방지:

sequenceDiagram
    InnoDB->>DWB: dirty page 먼저 doublewrite buffer 에 기록
    DWB->>SystemTablespace: flush
    InnoDB->>DataFile: 실제 데이터 파일에 쓰기
    Note over InnoDB: crash 시 DWB 로 복구 가능
  • OS 가 4KB 단위로 쓰지만 InnoDB page 는 16KB → partial write 발생 가능.
  • Doublewrite buffer 는 atomic write 보장 SSD (FusionIO 등) 에서 비활성화 가능.
-- 8.0.20+ 별도 파일로 분리됨
SHOW VARIABLES LIKE 'innodb_doublewrite%';

Adaptive Hash Index (AHI)

flowchart LR
    Query["반복 동일 조건 쿼리"] --> AHI["Adaptive Hash Index<br/>(메모리 해시)"]
    AHI -->|"hit (O(1))"| Row["Row (Buffer Pool)"]
    AHI -.->|"miss"| BTree["B-tree 탐색 (O(log N))"]
  • 자동으로 핫 B-tree 패턴을 해시 테이블 로 캐시.
  • 동일 쿼리 패턴 반복 시 B-tree depth 생략.
  • write-heavy 환경에서 오히려 경합 → 비활성화 검토.
SHOW ENGINE INNODB STATUS\G  -- AHI 사용률 확인
SET GLOBAL innodb_adaptive_hash_index = OFF;  -- 비활성화

Change Buffer (Insert Buffer)

보조 인덱스 페이지 가 메모리에 없을 때 나중에 일괄 적용:

flowchart LR
    Insert["INSERT / UPDATE"] --> Check{보조 인덱스 페이지<br/>Buffer Pool에?}
    Check -->|있음| Direct["즉시 적용"]
    Check -->|없음| CB["Change Buffer<br/>(시스템 테이블스페이스)"]
    CB -.->|"페이지 로드 시 merge"| Direct
  • 대량 INSERT 시 random I/O 감소 효과.
  • innodb_change_buffer_max_size (기본 25% of buffer pool).

Isolation Level (InnoDB 기본)

LevelInnoDB 기본의미
READ UNCOMMITTEDdirty read
READ COMMITTED다른 트랜잭션의 commit 된 것만
REPEATABLE READ기본같은 쿼리는 같은 결과 (snapshot)
SERIALIZABLE완전 격리

InnoDB 의 REPEATABLE READnext-key lock 으로 phantom read 방지. PostgreSQL 의 Read Committed 기본과 기본값이 다름.

자세한 건 transaction-isolation-levels.

Buffer Pool

flowchart LR
    Disk[("ibd files")] --> BP["Buffer Pool<br/>(innodb_buffer_pool_size)"]
    BP -->|hit| Client
    BP -.->|"LRU eviction"| Disk
    BP --> Young["Young 리스트<br/>(최근 접근)"]
    BP --> Old["Old 리스트<br/>(eviction 후보)"]
  • 메모리에 page 단위 (16KB) 캐시.
  • innodb_buffer_pool_size = 총 RAM 의 70-80% 가 운영 표준.
  • Hit ratio 확인: Innodb_buffer_pool_read_requests / Innodb_buffer_pool_reads.
  • 대용량 서버: innodb_buffer_pool_instances = 8 로 경합 분산.
-- 버퍼 풀 히트율 확인
SELECT FORMAT((1 - (Innodb_buffer_pool_reads / Innodb_buffer_pool_read_requests)) * 100, 2)
  AS hit_ratio
FROM (
  SELECT VARIABLE_VALUE AS Innodb_buffer_pool_reads
  FROM performance_schema.global_status WHERE VARIABLE_NAME = 'Innodb_buffer_pool_reads'
) r, (
  SELECT VARIABLE_VALUE AS Innodb_buffer_pool_read_requests
  FROM performance_schema.global_status WHERE VARIABLE_NAME = 'Innodb_buffer_pool_read_requests'
) rr;

Lock

Lock의미
Shared (S)다른 S 와 호환, X 와 충돌
Exclusive (X)단독
Intention (IS, IX)table-level 의도 표시
Record lockrow 단일
Gap lockrow 사이 간격
Next-key lockrecord + gap (phantom 방지)
Auto-inc lockAUTO_INCREMENT 동기

CAUTION

next-key lock 이 의도치 않게 넓은 범위 를 lock → deadlock 잦음. SHOW ENGINE INNODB STATUS\Gdeadlock log 확인.

Replication

flowchart LR
    Primary --> Binlog[("binlog")]
    Binlog --> R1["Replica 1"]
    Binlog --> R2["Replica 2"]
    Binlog --> R3["Replica 3"]
  • Async (기본): primary 가 즉시 OK
  • Semi-sync: 적어도 1개 replica 가 receive 후 OK
  • Group Replication: 다수 노드 합의

MySQL vs PostgreSQL

항목MySQLPostgreSQL
스토리지 엔진InnoDB (+ MyISAM legacy)단일
인덱스clustered (PK = data)heap + index
확장성 (extension)적음매우 많음
JSON 인덱싱OKJSONB + GIN 우수
복제binlog 기반streaming WAL
트랜잭션 DDL8.0+ 부분대부분 트랜잭션
운영 도구percona, mysql workbenchpsql + 풍부한 ecosystem
라이센스GPL (commercial 도)PostgreSQL License

흔한 함정

WARNING

  1. PK = UUID v4 = clustered index random write → 페이지 분할 폭증. ULID / 정렬 가능 UUID 또는 BIGINT.
  2. SELECT * 의 MVCC 비용 = old version chain 따라가기. unused 컬럼 안 가져오기.
  3. deadlock 무시 = SHOW ENGINE INNODB STATUS\GLATEST DEADLOCK 모니터링.
  4. binlog format 이 STATEMENT = 비결정적 함수 (NOW(), UUID()) → replica 와 다른 결과. ROW 또는 MIXED 권장.
  5. Doublewrite Buffer 비활성화 (일반 SSD) = partial write 위험. atomic write 지원 스토리지가 아닌 이상 활성화 유지.
  6. innodb_flush_log_at_trx_commit = 0 or 2 = crash 시 최대 1초 데이터 손실. 기본값 1 (fsync per commit) 권장.

관련 위키

이 글의 용어 (6개)
[DB Internals] B-Tree와 B+Tree 인덱싱database-internals
정의 B-Tree (B+ Tree) 는 거의 모든 RDB 의 인덱스 자료구조. balanced tree, 디스크 I/O 최소화 설계. 특징: - 균형 (balanced): 모든 …
[DB Internals] MVCC: Multi-Version Concurrency Controldatabase-internals
정의 MVCC (Multi-Versioning Concurrency Control) 는 트랜잭션 간 격리를 여러 버전의 row 로 구현. 동시 read / write 가 락 없이…
[DB] EXPLAIN 읽기: scan, join, sort, costdatabase-internals
정의 EXPLAIN = 쿼리 실행 계획 표시. EXPLAIN ANALYZE = 실제로 실행 + 실제 시간 측정. Scan 종류 | Scan | 의미 | 적합 | |---|---|…
[DB] PostgreSQL: 프로세스 모델, MVCC, WAL, 확장성database-internals
정의 PostgreSQL 은 오픈소스 ORDBMS. 1986 UC Berkeley POSTGRES 의 후예. MVCC, 확장 가능 타입, JSONB, full-text searc…
[DB] Transaction Isolation Levels: 완벽 가이드database-internals
정의 Transaction Isolation Level (트랜잭션 격리 수준) = 동시에 실행되는 여러 트랜잭션이 서로의 변경을 어디까지 볼 수 있는지 규정하는 수준. ACID …
[DB] WAL: Write-Ahead Log, crash recovery, replication 의 토대database-internals
정의 Write-Ahead Log (WAL) = 데이터 변경 전 로그를 먼저 디스크에 기록. 모든 모던 RDB / KV / 분산 시스템의 내구성 기반. 핵심 약속: 로그가 디스크…

💬 댓글

사이트 검색 / 명령어

검색

스크롤 = 확대/축소 · 드래그 = 이동 · 0 = 원래 크기 · ESC = 닫기