MySQL 성능최적화 (1)

1장 MySQL 아키텍처

MySQL 을 최상으로 활용하기 위해선 먼저 그 구조를 이해해야 한다.


참고: high-performance-mysql

  1. 최상층의 서비스는 MySQL 에 고유한 것은 아니며 대부분의 네트워크 기반 클라이언트 서버 또는 서버 도구에 필요한 서비스들로 연결 처리, 인증, 보안 등이 포함된다.
  2. 두 번째 층은 MySQL 의 두뇌라 할 수 있는 대부분의 기능이 있는데, 쿼리 파싱, 분석 또는 검토, 최적화, 캐싱, 내장 함수 등의 코드가 있다. 스토어드 프로시저, 트리거, 뷰 등의 스토리지 엔진에 관련된 모든 기능이 있다.
  3. 세 번째 층은 스토리지 엔진이 있는데, 이 엔진들이 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. 로깅하기

MyISAMArchive 스토리지 엔진은 오버헤드가 매우 낮으며 초당 수천개의 레코드를 삽입할 수 있으므로 이 경우에 적합하다.

로깅된 데이터의 요약 보고서를 만들어야 할 경우, MySQL 의 내장 복제 기능을 사용하여 데이터를 슬레이브 서버에 복제한다. 그 후, 슬레이브에 있는 데이터에 시간과 CPU 를 많이 소모하는 쿼리를 실행시키면 된다.

또 다른 옵션은 머지 테이블을 사용하는 것이다. 같은 테이블에 매번 로깅하는 대신, web_log_2018_01_01 과 같이 연도와 이름을 포함한 테이블에 로깅하도록 하는 것이다. 그 후 최신 테이블에서 insert 를 진행하는 동안 응용프로그램은 인터럽트 받지 않고 과거 테이블의 데이터를 분석할 수 있다.

2. 주문처리

트랜잭션이 필수 상황이다. InnoDB 가 가장 적합하다.

3. 주식 시세

MyISAM 은 주식 시세를 개인 관심용으로 분석하는 것 같은 일상적인 용도로 쓰기에 적합하다. 그러나 웹 서비스가 실시간 시세를 제공하며 사용자가 수천 명이고 트래픽이 많다면, 쿼리가 절대 대기 상태에 있어서는 안 된다. 여러 클라이언트가 읽기와 쓰기 권한을 동시에 테이블에 요청할 수 있으므로 행 수준 잠금을 쓰거나 데이터 갱신을 최소화하도록 설계해야 한다.