
1장 MySQL 아키텍처
MySQL 을 최상으로 활용하기 위해선 먼저 그 구조를 이해해야 한다.
- 최상층의 서비스는 MySQL 에 고유한 것은 아니며 대부분의 네트워크 기반 클라이언트 서버 또는 서버 도구에 필요한 서비스들로 연결 처리, 인증, 보안 등이 포함된다.
- 두 번째 층은 MySQL 의 두뇌라 할 수 있는 대부분의 기능이 있는데, 쿼리 파싱, 분석 또는 검토, 최적화, 캐싱, 내장 함수 등의 코드가 있다. 스토어드 프로시저, 트리거, 뷰 등의 스토리지 엔진에 관련된 모든 기능이 있다.
- 세 번째 층은 스토리지 엔진이 있는데, 이 엔진들이 MySQL 안에 저장된 데이터를 검색하고 저장하는 역할을 한다. 스토리지 엔진은 SQL 을 파싱하거나 서로 통신하지 않고 단순히 서버의 요구에 반응하는 역할만 한다. 서버는 스토리지 엔진 API 를 통해 통신하는데, 이러한 인터페이스는 서로 다른 스토리지 엔진 사이의 차이점을 감춰주어 쿼리 층 수준에서는 스토리지 엔진 간의 차이가 거의 나지 않게 만들어 준다.
InnoDB 엔진
InnoDB는 트랜잭션을 처리하기 위해 고안됐는데 대부분의 경우 롤백되지 않고 완료되는 짧은 트랜잭션이 많은 경우를 처리하기 좋게 되어 있다.InnoDB는 트랜잭션을 지원하는 스토리지 엔진 중 가장 유명하며 뛰어난 성능과 자동 장애 복구 기능으로 인해 트랜잭션이 팔요없는 상황에서도 널리 쓰인다.InnoDB는 데이터를 테이블스페이스라고 하는 한 개 이상의 일련의 데이터 파일에 저장한다. 테이블스페이스는InnoDB에서 자체적으로 관리하는 블랙박스라고 볼 수 있다.InnoDB는 동시성을 높이기 위해 MVCC 를 이용하며 SQL 표준인 4가지 격리 수준을 모두 구현한다. REPEATABLE READ 격리 수준을 기본으로 하며 팬텀 리드(Phantom Read)를 막는 넥스트-키 잠금 전략을 갖고 있다.InnoDB는 쿼리가 변경되는 행만 잠그는 것이 아니라 인덱스 구조 안의 레코드 사이의 갭(Gap)도 잠궈 팬텀 레코드가 삽입되지 않게 한다.InnoDB는 클러스터 인덱스(clustered index)위에 구성되는데, 매우 신속한 기본 키(Primary Key)조회가 가능하다. 그러나 보조 인덱스는 기본 키 행을 포함하므로 만약 기본 키가 크다면 다른 인덱스 또한 클 것이다.
적합한 엔진 선택하기
트랜잭션
InnoDB는 트랜잭션을 지원한다.MyISAM은 트랜잭션이 필요 없거나 SELECT, INSERT 쿼리를 많이 사용하는 경우에 적합한 엔진인데 로깅과 같은 응용프로그램의 특수 구성 요소가 이 경우에 속한다.
동시성
- 동시에 삽입과 읽기만 하면 된다면
MyISAM으로도 충분하지만, 여러 작업이 서로 인터럽트 없이 동시에 실행되려면 행 수준 잠금 기능이 있는 엔진을 선택해야 한다.
특수기능
- 많은 응용프로그램은 클러스터 인덱스 최적화에 의존한다 (
InnoDB,SolidDB) - 전문 검색의 경우 지원하는 엔진은
MyISAM밖에 없다.
실용 예제
1. 로깅하기
MyISAM 과 Archive 스토리지 엔진은 오버헤드가 매우 낮으며 초당 수천개의 레코드를 삽입할 수 있으므로 이 경우에 적합하다.
로깅된 데이터의 요약 보고서를 만들어야 할 경우, MySQL 의 내장 복제 기능을 사용하여 데이터를 슬레이브 서버에 복제한다. 그 후, 슬레이브에 있는 데이터에 시간과 CPU 를 많이 소모하는 쿼리를 실행시키면 된다.
또 다른 옵션은 머지 테이블을 사용하는 것이다. 같은 테이블에 매번 로깅하는 대신, web_log_2018_01_01 과 같이 연도와 이름을 포함한 테이블에 로깅하도록 하는 것이다. 그 후 최신 테이블에서 insert 를 진행하는 동안 응용프로그램은 인터럽트 받지 않고 과거 테이블의 데이터를 분석할 수 있다.
2. 주문처리
트랜잭션이 필수 상황이다. InnoDB 가 가장 적합하다.
3. 주식 시세
MyISAM 은 주식 시세를 개인 관심용으로 분석하는 것 같은 일상적인 용도로 쓰기에 적합하다. 그러나 웹 서비스가 실시간 시세를 제공하며 사용자가 수천 명이고 트래픽이 많다면, 쿼리가 절대 대기 상태에 있어서는 안 된다. 여러 클라이언트가 읽기와 쓰기 권한을 동시에 테이블에 요청할 수 있으므로 행 수준 잠금을 쓰거나 데이터 갱신을 최소화하도록 설계해야 한다.
