2. InnoDB 스토리지 엔진 아키텍처
MySQL의 스토리지 엔진 가운데 가장 많이 사용
거의 유일하게 레코드 기반의 잠금 제공 -> ↑ 동시성 처리 가능, 안정적, 성능 뛰어남
1) 프라이머리 키에 의한 클러스터링
- 프라이머리 키를 기준으로 클러스터링되어 저장 = 프라이머리 키 값의 순서대로 디스크에 저장
- 프라이머리 키 = 클러스터링 인덱스 -> 프라이머리 키를 이용한 레인지 스캔은 상당히 빨리 처리
- => 쿼리 실행 계획에서 프라이머리 키: 다른 보조 인덱스에 비해 비중 높게 설정(다른 보조 인덱스보다 선택될 확률 ↑)
- 모든 세컨더리 인덱스 -> 프라이머리 키의 값(레코드 주소 대신)을 논리적인 주소로 사용
- 오라클 DBMS의 IOT(Index organized table) -> InnoDB에서는 일반적인 테이블 구조
MyISAM 스토리지 엔진: 클러스터링 키 지원 X (vs. InnoDB 스토리지 엔진)
-> 프라이머리 키와 세컨더리 인덱스의 구조적 차이 X/ 프라이머리 키 = 유니크 제약을 가진 세컨더리 인덱스
MyISAM 테이블의 프라이머리 키를 포함한 모든 인덱스: 물리적인 레코드의 주소 값(ROWID) 가짐
2) 외래 키 지원
- InnoDB 스토리지 엔진 레벨에서 지원하는 기능, MyISAM or MEMORY 테이블에서 사용 X
- 외래 키: 데이터베이스 서버 운영의 불편함 -> 서비스용 데이터베이스에서는 생성하지 X 경우도 자주 있음
- 개발 환경의 데이터베이스에서는 좋은 가이드 역할할 수 있음
- 부모/자식 테이블 해당 칼럼에 인덱스 생성
- 변경: 부모/자식 테이블에 데이터가 있는지 체크 -> 잠금이 여러 테이블에 전파 => 데드락 발생하는 경우 ↑
- 수동으로 데이터 적재 or 스키마 변경 등의 관리 작업이 실패할 수 있음
- 부모/자식 테이블의 관계 명확히 파악 -> 순서대로 작업 => 문제 X
- But, 외래키가 복잡하게 얽힌 경우 간단 X
- `SET foreign_key_checks=OFF`: 외래 키 관계에 대한 체크 작업 일시적으로 멈춤
- 레코드 적재 or 삽입 등의 작업도 부가적인 체크 필요 X => 훨씬 빠르게 처리할 수 있음
- 부모/자식 테이블 간의 관계가 깨진 상태로 그대로 유지해도 된다 (X)
- ex. 외래 키 체크를 일시적으로 중지한 상태에서 외래 키 관계를 가진 부모 테이블의 레코드 삭제
-> 반드시 자식 테이블의 레코드 삭제 => 일관성을 맞춰준 후 다시 외래 키 체크 기능 활성화 - 외래 키 관계의 부모 테이블에 대한 작업(`ON DELETE CASCADE`, `ON UPDATE CASCADE` 옵션) 무시
3) MVCC(Multi Version Concurrency Control)
레코드 레벨의 트랜잭션을 지원하는 DBMS가 제공하는 기능
목적: 잠금을 사용하지 않는 일관된 읽기 제공
InnoDB는 언두 로그(Undo log) 이용해 구현
멀티 비전(multi version): 하나의 레코드에 대해 여러 개의 버전이 동시에 관리 된다
<격리 수준(Isolation level):`READ_COMMITED`인 MySQL 서버에서 테이블의 데이터 변경 처리하는 방법>
INSERT INTO member (m_id, m_name, m_area) VALUES (12, '홍길동', '서울');
COMMIT;
UPDATE member SET m_area='경기' WHERE m_id=12;
`UPDATE` 문장 실행 -> 커밋 실행 여부와 관계X InnoDB의 버퍼 풀은 새로운 값인 '경기'로 업데이트
/ 디스크 데이터 파일에는 체크포인트 or InnoDB의 Write 스레드에 의해 새로운 값으로 업데이트 OX
(InnoDB는 ACID 보장 -> 일반적으로 InnoDB의 버퍼 풀과 데이터 파일은 동일한 상태)
`COMMIT` or `ROLLBACK` X 다른 사용자가 작업 중인 레코드 조회(`SELECT * FROM member WHERE m_id=12`)
-> MySQL 서버의 시스템 변수(`transaction_isolation`)에 설정된 격리 수준(Isolation levle)에 따라 다름
- `READ_UNCOMMITED`
- InnoDB 버퍼 풀이 현재 가지고 있는 변경된 데이터 읽어서 반환
- `READ_COMMITED`, `REPEATBALE_READ`, `SERIALIZABALE`
- 아직 `COMMIT` X -> 변경되기 이전의 내용을 보관하고 있는 언두 영역의 데이터 반환
=> MVCC: 하나의 레코드에 대해 2개의 버전 유지, 필요에 따라 어느 데이터가 보여지는지 상황에 따라 달라지는 구조
`UPDATE` -> InnoDB 버퍼 풀은 즉시 새로운 데이터로 변경, 기존 데이터는 언두 영역으로 복사되는 과정
- `COMMIT`: 더 이상의 변경 작업 X 지금 상태를 영구적인 데이터로 만듦
- 언두 영역의 백업 데이터가 항상 바로 삭제 X, 필요로 하는 트랜잭션이 더 없을 때 삭제 O
- `ROLLBACK`: 언두 영역에 있는 백업된 데이터를 InnoDB 버퍼 풀로 다시 복구, 언두 영역의 내용 삭제
4) 잠금 없는 일관된 읽기(Non-Locking Consistent Read)
MVCC 기술 이용 -> 잠금을 걸지 않고 읽기 작업 수행
=> 다른 트랜잭션이 가지고 있는 잠금 기다리지 X 읽기 작업 가능
격리 수준: `READ_UNCOMMITED`, `READ_COMMITED`, `REPEATBALE_READ` (`SERIALIZABALE` X)
-> 순수한 읽기(`SELECT`) 작업(`INSERT`와 연결 X): 다른 트랜잭션의 변경 작업 관련 없이 항상 잠금 대기 X 바로 실행
IF. 특정 사용자) 레코드 변경, 아직 `COMMIT` 수행 X -> 이 트랜잭션이 다른 사용자의 `SELECT` 작업 방해 X
=> 잠금 없는 일관된 읽기: InnoDB에서는 변경되기 전의 데이터를 읽기 위해 언두 로그 사용
오랜 시간 동안 활성 상태인 트랜잭션 -> MySQL 서버 느려지거나 문제 발생
=> 일관된 읽기를 위해 언두 로그 삭제 X 계속 유지하기 때문에 발생
=> 트랜잭션 시작됐다면 가능한 빨리 `COMMIT` or `ROLLBACK` ~> 트랜잭션 완료하는 것이 좋음
5) 자동 데드락 감지
- 잠금이 교착 상태에 빠지지 않았는지 체크 -> 잠금 대기 목록을 그래프(Wait-for List)로 관리
- 데드락 감지 스레드) 주기적으로 잠금 대기 그래프 검사 -> 교착 상태에 빠진 트랜잭션 찾아서 하나를 강제 종료
- 잠금 상태 변경 X -> 잠금 목록이 저장된 리스트(잠금 테이블)에 새로운 잠금 걸고 데드락 스레드 찾음
- 어느 트랜잭션을 먼저 강제 종료할 것인지 판단 기준: 트랜잭션의 언두 로그 양
- 언두 로그 레코드 ↓ = 롤백을 해도 언두 처리를 해야 할 내용 ↓ -> 트랜잭션 강제 롤백으로 인한 MySQL 서버 부하 ↓
상위 레이어인 MySQL 엔진에서 관리되는 테이블 잠금(`LOCK TABLES` 명령으로 잠긴 테이블) 볼 수 X
-> 데드락 감지 불확실할 수 있음
=> `innodb_table_locks` 시스템 변수 활성화: InnoDB 스토리지 엔진 내부의 레코드 잠금, 테이블 레벨의 잠금 감지 O
일반적인 서비스에서 데드락 찾아내는 작업 크게 부담 X
But, 동시 처리 스레드 매우 ↑ or 각 트랜잭션이 가진 잠금의 개수 ↑ -> 데드락 감지 스레드 느려짐
-> 서비스 쿼리를 처리 중인 스레드는 더 이상 작업 진행 X 대기하면서 서비스에 악영향 미치게 됨
=> 데드락 감지 스레드는 더 많은 CPU 자원 소모할 수 있음
`innodb_deadlock_detect=OFF`: 데드락 감지 스레드 작동 X
2개 이상의 트랜잭션이 상대방이 가진 잠금에 요구하는 상황(데드락 상황) 발생해도 누군가가 중재 X -> 무한정 대기
But, `innodb_lock_wait_timeout` 시스템 변수 활성화
: 데드락 상황에서 일정 시간이 지나면 자동으로 요청 실패, 에러 메시지 반환
/ 초 단위로 설정 O(권장: 기본값인 50초보다 훨씬 낮은 값), 잠금 설정한 시간 동안 획득 X -> 쿼리 실패, 에러 반환
6) 자동화된 장애 복구
손실 or 장애로부터 데이터를 보호하기 위한 여러 가지 메커니즘 탑재
-> MySQL 서버가 시작될 때 완료 X 트랜잭션 or 디스크에 일부만 기록된(Partial write) 데이터 페이지 등 일련의 복구 작업 자동
InnoDB 스토리지 엔진은 매우 견고 -> 데이터 파일 손상 or MySQL 서버가 시작되지 못하는 경우 거의 발생 X
But, 디스크 or 서버 하드웨어 잉슈 -> InnoDB 스토리지 엔진이 자동으로 복구를 못하는 경우 발생할 수 있음
- 시작될 때 항상 자동으로 복구 수행
- 자동으로 복구 X 손상 O -> 자동 복구 멈추고 MySQL 서버 종료
- `innodb_force_recovery` 시스템 변수 설정해서 MySQL 서버 시작
- MySQL 서버 시작될 때 InnoDB 스토리지 엔진이 데이터 파일 or 로그 파일의 손상 여부 검사 과정 -> 선별적 진행
- 로그 파일 손상 -> 6으로 설정 / 데이터 파일 손상 -> 1로 설정
- 어떤 부분이 문제 X -> 1부터 6까지 변경하면서 재시작
/ 값이 커질수록 심각한 상황 -> 데이터 손실 가능성 ↑ 복구 가능성 ↓
MySQL 서버 기동, InnoDB 테이블 인식 O
-> `mysqldump` 이용해 데이터를 가능한 만큼 백업, 그 데이터로 DB와 테이블 다시 생성하는 것이 좋음
`innodb_force_recovery`가 0이 아닌 복구 모드: `SELECT` 이외의 `INSERT`, `UPDATE`, `DELETE` 쿼리 수행 X
- 1(`SRV_FORCE_IGNORE_CORRUPT`)
- 테이블스페이스의 데이터 or 인덱스 페이지에서 손상된 부분이 발견돼도 무시, MySQL 서버 시작
- 에러 로그 파일: 'Database page corruption on disk or a failed'
- `mysqldump` 프로그램 or `SELECT INTO OUTFILE ...` 명령 이용해 덤프해서 데이터베이스 다시 구축하는 것이 좋음
- 2(`SRV_FORCE_NO_BACKGROUND`)
- 백그라운드 스레드 중 메인 스레드 시작 X MySQL 서버 시작
- InnoDB는 쿼리 처리를 위해 여러 종류의 백그라운드 스레드 동시에 사용
- 트랜잭션 롤백 -> 언두 데이터 관리
- 트랜잭션이 커밋되어 불필요한 언두 데이터 -> 메인 스레드) 주기적으로 삭제(Undo purge)
- 메인 스레드가 언두 데이터를 삭제하는 과정에서 장애가 발생한 경우 사용
- 백그라운드 스레드 중 메인 스레드 시작 X MySQL 서버 시작
- 3(`SRV_FORCE_NO_TRX_UNDO`)
- 트랜잭션 실행 -> 롤백에 대비해 변경 전의 데이터를 언두 영역에 기록
- MySQL 서버는 다시 시작하면서 언두 영역의 데이터를 먼저 데이터 파일에 적용
-> 리두 로그의 내용을 다시 덮어써서 장애 시점의 데이터 상태를 만들어냄 - 커밋 X 트랜잭션의 작업 롤백 X 그대로 놔둠
- 정상적인 MySQL 서버의 시작: 최종적으로 커밋 X 트랜잭션은 롤백
- 커밋 X 트랜잭션은 계속 그 상태로 남아 있게 MySQL 서버를 시작하는 모드
- MySQL 서버 시작 -> `mysqldump` 이용해 데이터를 백업해서 다시 데이터베이스를 구축하는 것이 좋음
- 4(`SRV_FORCE_NO_IBUF_MERGE`)
- `INSERT`, `UPDATE`, `DELETE` 등의 데이터 변경으로 인한 인덱스 변경 작업을 상황에 따라 즉시 처리
or 인서트 버퍼에 저장해두고 나중에 처리- 언제 데이터 파일에 병합(Merge)될지 알 수 X/ MySQL을 종료해도 병합되지 않을 수 있음
- IF. MySQL이 재시작되면서 인서트 버퍼의 손상 감지 -> InnoDB 에러 발생, MySQL 서버 시작 X
- 인서트 버퍼의 내용 무시, 강제로 MySQL 시작되게 함
- 인서트 버퍼: 실제 데이터 관련된 부분 X 인덱스에 관련된 부분 -> 테이블을 덤프한 후 다시 데이터베이스 구축
- `INSERT`, `UPDATE`, `DELETE` 등의 데이터 변경으로 인한 인덱스 변경 작업을 상황에 따라 즉시 처리
- 5(`SRV_FORCE_NO_UNDO_LOG_SCAN`)
- MySQL 서버가 장애 or 정상적으로 종료되는 시점에 진행 중인 트랜잭션 O
-> MySQL은 단순히 커넥션 강제로 끊어 버리고 별도의 정리 작업 없이 종료 - 다시 시작하면 언두 레코드 -> 데이터 페이지 복구/ 리두 로그 적용 -> 종료/장애 발생 시점의 상태 재현
/ 마지막으로 커밋 X 트랜잭션에서 변경한 작업 모두 롤백 처리- 언두 로그 사용 X -> InnoDB 엔진의 에러로 MySQL 서버 시작 X
- MySQL 서버가 장애 or 정상적으로 종료되는 시점에 진행 중인 트랜잭션 O
- 6(`SRV_FORCE_NO_LOG_REPO`)
- InnoDB 엔진은 리두 로그를 무시한 채로 MySQL 시작
- 리두 로그 손상 -> MySQL 서버 시작 X
- 커밋됐어도 리두 로그에만 기록, 데이터 파일에 기록 X 데이터는 모두 무시
= 마지막 체크포인트 시점의 데이터만 남게 됨
- 기존 InnoDB의 리두 로그는 모두 삭제(or 별도의 디렉터리에 백업), MySQL 서버를 시작하는 것이 좋음
- MySQL 서버가 시작하면서 리두 로그 X -> 새로 생성 => 별도의 파일 생성할 필요 X
- `mysqldump` 이용해 데이터 모두 백업해서 MySQL 서버 새로 구축하는 것이 좋음
- InnoDB 엔진은 리두 로그를 무시한 채로 MySQL 시작
여전히 MySQL 서버 시작 X -> 백업을 이용해 다시 구축하는 방법밖에 없음
백업 O -> 마지막 백업으로 데이터베이스 새로 구축, 바이너리 로그 -> 최대한 장애 시점까지의 데이터를 복구 O
마지막 풀 백업 시점 ~ 장애 시점까지의 바이너리 로그 O -> InnoDB의 복구보다 풀 백업, 바이너리 로그로 복구가 데이터 손실 ↓
/ 백업 O But, 바이너리 로그 X -> 마지막 백업 시점까지만 복구할 수 있음
7) InnoDB 버퍼 풀
- InnoDB 스토리지 엔진에서 가장 핵심적인 부분
- 디스크의 데이터 파일 or 인덱스 정보를 메모리에 캐시해 두는 공간
- 쓰기 작업 지연 -> 일괄 작업으로 처리할 수 있게 해주는 버퍼 역할도 함
- => 변경된 데이터 모아서 처리 -> 랜덤한 디스크 작업의 횟수 ↓
- `INSERT`, `UPDATE`, `DELETE`처럼 데이터를 변경하는 쿼리
: 데이터 파일의 이곳저곳에 위치한 레코드 변경 -> 랜덤한 디스크 작업 발생
버퍼 풀의 크기 설정
버퍼 풀의 구조
버퍼 풀과 리두 로그
버퍼 풀 플러시(Buffer Pool Flush)
플러시 리스트 플러시
LRU 리스트 플러시
버퍼 풀 상태 백업 및 복구
버퍼 풀의 적재 내용 확인
8) Double Write Buffer
9) 언두 로그(Undo Log)
InnoDB 스토리지 엔진은 트랜잭션, 격리 수준 보장
-> DML(`INSERT`, `UPDATE`, `DELETE`)로 변경되기 이전 버전의 데이터를 별도로 백업
=> 이렇게 백업된 데이터: 언두 로그
- 트랜잭션 보장
- 트랜잭션 롤백 -> 트랜잭션 도중 변경된 데이터를 변경 전 데이터로 복구해야 함
-> 이때 언두 로그에 백업해둔 이전 버전의 데이터를 이용해 복구
- 트랜잭션 롤백 -> 트랜잭션 도중 변경된 데이터를 변경 전 데이터로 복구해야 함
- 격리 수준 보장
- 특정 커넥션에서 데이터를 변경하는 도중에 다른 커넥션에서 데이터 조회
-> 트랜잭션 격리 수준에 맞게 변경 중인 레코드 읽지 X 언두 로그에 백업해둔 데이터를 읽어서 반환하기도 함
- 특정 커넥션에서 데이터를 변경하는 도중에 다른 커넥션에서 데이터 조회
스토리지 엔진에서 중요한 역할 But, 관리 비용 ↑
언두 로그 레코드 모니터링
언두 영역: `INSERT`, `UPDATE`, `DELETE`같은 문장으로 데이터 변경했을 때 변경되기 전의 데이터(이전 데이터) 보관하는 곳
언두 로그 데이터 용도
- 트랜잭션의 롤백 대비용
- 트랜잭션의 격리 수준 유지, ↑ 동시성 제공
동시에 여러 트랜잭션이 데이터 변경/조회 -> 한 트랜잭션의 작업 내용이 다른 트랜잭션에 어떻게 보일지 결정하는 기준
언두 테이블스페이스(Undo Tablesapce) 관리
언두 테이블스페이스: 언두 로그가 저장되는 공간
- 5.6 이전 버전: 언두 로그 모두 시스템 테이블스페이스(ibdata.ibd)에 저장
- (-) 시스템 테이블스페이스의 언두 로그: MySQL 서버가 초기화될 때 생성 -> 확장의 한계
- 5.6 버전: `innodb_undo_tablespaces` 시스템 변수
- 2보다 큰 값 설정 -> 언두 로그를 시스템 테이블 스페이스에 저장 X 별도의 언두 로그 파일 이용
- (-) 0으로 설정 -> 여전히 동일하게 언두 로그가 시스템 테이블스페이스에 저장(= 5.6 이전 버전)
- 8.0 버전(8.0.14 버전부터): `innodb_undo_tablespaces` 시스템 변수 X
- 항상 시스템 테이블스페이스 외부의 별도 로그 파일에 기록
하나의 언두 테이블스페이스는 1개 이상 128개 이하의 롤백 세그먼트 가짐
/ 롤백 세그먼트는 1개 이상의 언두 슬롯(Undo Slot) 가짐
1개의 롤백 세그먼트: (InnoDB의 페이지 크기 / 16바이트) 만큼의 언두 슬롯 가짐
ex. InnoDB의 페이지 크기: 16KB -> 1개의 롤백 세그먼트: 1024개의 언두 슬롯 가짐
하나의 트랜잭션이 필요로 하는 언두 슬롯 개수: `INSERT`, `UPDATE`, `DELETE` 문장의 특성에 따라 최대 4개까지 언두 슬롯 사용
일반적으로는 트랜잭션이 임시 테이블 사용 X -> 약 2개의 언두 슬롯 필요
=> 최대 동시 트랜잭션 수 = (InnoDB 페이지 크기) / 16 * (롤백 세그먼트 개수) * (언두 테이블 개수)
ex. 16KB InnoDB에서 기본 설정(`innodb_undo_tablespaces=2`, innodb_rollback_segments=128`) 사용
-> 16 * 1024 / 16 * 128 * 2 / 2 = 131072 개 정도의 트랜잭션이 동시에 처리 가능
언두 로그 공간이 남는 것은 문제 X But, 부족한 경우에는 트랜잭션 시작 ㅌX
8.0 버전: `CREATE UNDO TABLESPACE` or `DROP TABLESPACE` -> 새로운 언두 테이블스페이스 동적으로 추가/삭제
Undo tablespace truncate
: 언두 테이블스페이스 공간을 필요한 만큼만 남기고 불필요하거나 과도하게 할당된 공간을 운영체제로 반납하는 것
<언두 테이블스페이스의 불필요한 공간을 잘라내는(Truncate) 방법(8.0 부터)>
- 자동 모드
- 수동 모드
ALTER UNDO TABLESPACE tablespace_name SET INACTIVE;
10) 체인지 버퍼
11) 리두 로그(Redo Log) 및 로그 버퍼
리두 로그
- 트랜잭션의 4가지 요소인 ACID 중에서 D(Durable, 영속성)과 가장 밀접하게 연관
- MySQL 서버가 비정상적으로 종료 -> 데이터 파일에 기록 X 데이터 잃지 않게 해주는 안전장치
대부분 데이터베이스 서버) 데이터 변경 내용 -> 로그로 먼저 기록
리두 로그 = WAL(Write Ahead Log): 데이터를 디스크에 기록하기 전에 먼저 기록되는 로그
거의 모든 DBMS에서 데이터 파일은 쓰기 < 읽기 성능 고려한 자료 구조 가지고 있음
-> 데이터 파일 쓰기는 디스크의 랜덤 액세스 필요 => 변경된 데이터를 데이터 파일에 기록하려면 상대적으로 비용 ↑
-> 성능 저하 막기 위한 데이터베이스 서버는 쓰기 비용 ↓ 자료 구조를 가진 리두 로그 가지고 있음
/ 비정상 종료 발생 -> 리두 로그 ~> 데이터 파일을 다시 서버가 종료되기 직전의 상태로 복구
데이터베이스 서버: ACID + 성능 중요 -> (InnoDB 버퍼 풀, 로그 버퍼) 자료 구조 가지고 있음
InnoDB 버퍼 풀: 데이터 파일 + 리두 로그 버퍼링/ 로그 버퍼: 리두 로그 버퍼링
<MySQL 서버 비정상 종료 -> InnoDB 스토리지 엔진의 데이터 파일: 일관 X 데이터>
- 커밋 But, 데이터 파일에 기록 X 데이터
- 리두 로그에 저장된 데이터 -> 데이터 파일에 다시 복사
- 롤백 But, 데이터 파일에 기록 O 데이터
- 리두 로그로 해결 X
- 변경이 커밋 or 롤백 or 트랜잭션의 실행 중간 상태였는지 확인
- 변경되기 전 데이터를 가진 언두 로그의 내용을 가져와 데이터 파일에 복사
- 리두 로그로 해결 X
데이터베이스 서버에서 리두 로그는 트랜잭션 커밋 -> 즉시 디스크로 기록되도록 시스템 변수 설정하는 것 권장
=> 서버가 비정상적으로 종료됐을 때 직전까지의 트랜잭션 커밋 내용이 리두 로그에 기록
But, 부하 ↑ -> `innodb_flush_log_at_trx_commit` 시스템 변수
: InnoDB 스토리지 엔진에서 리두 로그를 어느 주기로 디스크에 동기화할지 결정
- 0: 1초에 한 번씩 리두 로그 -> 디스크로 기록(write), 동기화(sync)
- 서버가 비정상 종료 -> 최대 1초 동안의 트랜잭션은 커밋됐다고 해도 해당 트랜잭션에서 변경한 데이터는 사라질 수 있음
- 1: 매번 트랜잭션이 커밋될 때마다 디스크로 기록, 동기화
- 트랜잭션이 일단 커밋 -> 해당 트랜잭션에서 변경한 데이터는 사라짐
- 2: 매번 트랜잭션이 커밋될 때마다 디스크로 기록, 동기화 1초에 1번
- 트랜잭션이 일단 커밋 -> 변경 내용이 운영체제의 메모리 버퍼로 기록되는 것이 보장
=> MySQL 서버가 비정상 종료돼도 운영체제 정상 작동 -> 해당 트랜잭션의 데이터 사라지지 X - MySQL 서버, 운영체제 비정상 종료 -> 최근 1초 동안의 트랜잭션의 데이터는 사라질 수 있음
- 트랜잭션이 일단 커밋 -> 변경 내용이 운영체제의 메모리 버퍼로 기록되는 것이 보장
리두 로그 아카이빙
8.0 버전부터: InnoDB의 스토리지 엔진의 리두 로그를 아카이빙할 수 있는 기능 추가
리두 로그 활성화 및 비활성화
MySQL 서버가 비정상적으로 종료 -> 데이터 파일에 기록 X 트랜잭션 복구 => 항상 활성화
트랜잭션이 커밋돼도 데이터 파일은 즉시 디스크로 동기화 X But, 리두 로그(트랜잭션 로그)는 항상 디스크로 기록 O
8.0 버전부터: 수동으로 리두 로그 활성화/비활성화
-> 데이터 복구 or 대용량 데이터 한번에 적재하는 경우: 비활성화 -> 데이터 적재 시간 ↓
// 비활성화
ALTER INSTANCE DISABLE INNODB REDO_LOG;
// 활성화
ALTER INSATNCE ENABLE INNODB REDO_LOG;
// 상태 확인
SHOW GLOBAL SATUS LIKE 'Innodb_redo_log_enabled';
MySQL 서버는 항상 새롭게 시작될 때 자신이 가진 리두 로그에서 데이터 파일에 기록되지 못한 데이터가 있는지 검사
IF. 리두 로그 비활성화된 상태 + MySQL 서버 비정상 종료 -> 리두 로그를 이용한 복구 불가능
=> MySQL 서버 정상적으로 시작되지 못할 수 있음
-> 데이터가 중요하지 않더라도 리두 로그를 활성화
-> MySQL 서버가 비정상적으로 종료돼도 특정 시점의 일관된 데이터를 가질 수 있게 하는 것이 좋음
(일부 손실돼도 괜찮다면 비활성화보다 시스템 변수 0 or 2로 설정해서 사용할 것을 권장)
리두 로그 비활성화된 상태에서 MySQL 서버 재시작: `innodb_force_recovery=6`
12) 어댑티브 해시 인덱스
인덴스 = 테이블에 사용자가 생성해둔 B-Tree 인덱스
13) InnoDB와 MyISAM, MEMORY 스토리지 엔진 비교
지금까지는 MyISAM이 기본 스토리지 엔진으로 사용되는 경우가 많았음
5.5 버전부터: InnoDB 스토리지 엔진이 기본 엔진으로 채택, MySQL 서버의 시스템 테이블: MyISAM 테이블
사용자 인증 관련된 정보, 복제 관련된 정보 저장된 mysql DB의 테이블
8.0 버전: 모든 시스템 테이블이 InnoDB 스토리지 엔진으로 교체
공간 좌표 건색 or 전문 검색 기능이 모두 InnoDB 스토리지 엔진을 지원하도록 개선
이후 버전에서 MyISAM 스토리지 엔진이 없어질 것으로 예상
MyISAM or MEMORY 스토리지 엔진에 대한 성능상 장점을 기대하는 사용자
-> 5.1, 5.5 버전이면 의미 있는 비교 But, 8.0 버전: MyISAM 스토리지 엔진만이 가지는 장점 X
- Memory 스토리지 엔진 < InnoDB 스토리지 엔진 동시 처리 성능
- 모든 처리를 메모리에서만 수행 -> 빠를 것이라고 예상
=> 하나의 스레드에서만 데이터를 읽고 쓴다면 InnoDB보다 빠를 수 있음 - But, MySQL 서버는 일반적으로 온라인 트랜잭션 처리를 위한 목적으로 사용, 동시 처리 성능 매우 중요
- 동시에 몇십 or 몇백 개의 클라이언트에서 쿼리 요청 실행되는 경우
: MEMORY 스토리지 엔진은 테이블 수준의 잠금 -> 제대로 된 성능 X
- 동시에 몇십 or 몇백 개의 클라이언트에서 쿼리 요청 실행되는 경우
- MySQL 서버는 사용자의 쿼리를 처리 -> 내부적으로 임시 테이블 사용 O
- 5.7 버전까지: MOMEORY 스토리지 엔진이 내부 임시 테이블의 용도로 사용
- (-) 가변 길이 타입의 컬럼 지원 X
- 8.0 버전부터: TempTable 스토리지 엔진(MEMORY 스토리지 엔진 대체) 사용
- `internal_tmp_mem_storage_engine` 시스템 변수
: 내부 임시 테이블 -> TempTable/MEMORY 엔진 선택(기본값: TempTable)
- `internal_tmp_mem_storage_engine` 시스템 변수
- 5.7 버전까지: MOMEORY 스토리지 엔진이 내부 임시 테이블의 용도로 사용
- 모든 처리를 메모리에서만 수행 -> 빠를 것이라고 예상
출처
GitHub - wikibook/realmysql80: 《Real MySQL 8.0》 예제 파일
《Real MySQL 8.0》 예제 파일. Contribute to wikibook/realmysql80 development by creating an account on GitHub.
github.com
'💻 > 데이터베이스' 카테고리의 다른 글
[Real MySQL 8.0 1] 0.6. 데이터 압축 (0) | 2025.01.27 |
---|---|
[Real MySQL 8.0 1] 0.5 트랜잭션과 잠금 (0) | 2025.01.24 |
[Real MySQL 8.0 1] 04. 아키텍처 - 3. MyISAM 스토리지 엔진 아키텍처 / 4. MySQL 로그 파일 (0) | 2025.01.24 |
[Real MySQL 8.0 1] 04. 아키텍처 - 1. MySQL 엔진 아키텍처 (0) | 2025.01.23 |
[Real MySQL 8.0 1] 03. 사용자 및 권한 (0) | 2025.01.23 |