데이터베이스 쿼리 성능을 튜닝하는데 가장 먼저 해야할 일, 바로 실행 계획 분석이다.
당연히 INDEX SCAN
할거라 생각했던 쿼리도, 막상 실행 계획을 보면 FULL SCAN
인 경우가 많다.
실제로 실행 계획을 제대로 확인하지 않아 서버 장애가 발생한 사례가 있다.
커밋 전 실행 계획을 제대로 확인해 사고를 미연에 방지하자.
실행 계획을 알고 싶을 때 사용하는 기본 명령어다.
EXPLAIN [EXTENDED] SELECT ... FROM ... WHERE ...
구분 | 설명 |
---|---|
id | select 아이디로 SELECT를 구분하는 번호 |
table | 참조하는 테이블 |
select_type | select에 대한 타입 |
type | 조인 혹은 조회 타입 |
possible_keys | 데이터를 조회할 때 DB에서 사용할 수 있는 인덱스 리스트 |
key | 실제로 사용할 인덱스 |
key_len | 실제로 사용할 인덱스의 길이 |
ref | Key 안의 인덱스와 비교하는 컬럼(상수) |
rows | 쿼리 실행 시 조사하는 행 수립 |
extra | 추가 정보 |
SELECT의 번호다.
서브 쿼리
나 UNION
이 없다면 SELECT는 하나밖에 없기 때문에 모든 행에 대해 1이란 값이 부여된다.
어떤 테이블에 대한 접근을 표시하고 있는지 표시한다.
alias 명이 있는 경우 해당 명으로 표시된다.
구분 | 설명 |
---|---|
SIMPLE | 단순 SELECT (Union 이나 Sub Query 가 없는 SELECT 문) |
PRIMARY | Sub Query를 사용할 경우 Sub Query의 외부에 있는 쿼리(첫번째 쿼리), UNION 을 사용할 경우 UNION의 첫 번째 SELECT 쿼리 |
UNION | UNION 쿼리에서 Primary를 제외한 나머지 SELECT |
DEPENDENT_UNION | UNION 과 동일하나, 외부쿼리에 의존적임 (값을 공급 받음) |
UNION_RESULT | UNION 쿼리의 결과물 |
SUBQUERY | Sub Query 또는 Sub Query를 구성하는 여러 쿼리 중 첫 번째 SELECT문 |
DEPENDENT_SUBQUERY | Sub Query 와 동일하나, 외곽쿼리에 의존적임 (값을 공급 받음) |
DERIVED | SELECT로 추출된 테이블 (FROM 절 에서의 서브쿼리 또는 Inline View) |
UNCACHEABLE SUBQUERY | Sub Query와 동일하지만 공급되는 모든 값에 대해 Sub Query를 재처리. 외부쿼리에서 공급되는 값이 동이라더라도 Cache된 결과를 사용할 수 없음 |
UNCACHEABLE UNION | UNION 과 동일하지만 공급되는 모든 값에 대하여 UNION 쿼리를 재처리 |
쿼리 성능 판별 시 가장 주되게 보는 항목이다.
구분 | 설명 |
---|---|
system | 테이블에 단 한개의 데이터만 있는 경우 |
const | SELECT에서 Primary Key 혹은 Unique Key를 살수로 조회하는 경우로 많아야 한 건의 데이터만 있음 |
eq_ref | 조인을 할 때 Primary Key |
ref | 조인을 할 때 Primary Key 혹은 Unique Key가 아닌 Key로 매칭하는 경우 |
ref_or_null | ref 와 같지만 null 이 추가되어 검색되는 경우 |
index_merge | 두 개의 인덱스가 병합되어 검색이 이루어지는 경우 |
unique_subquery | 다음과 같이 IN 절 안의 서브쿼리에서 Primary Key가 오는 특수한 경우 SELECT * FROM tab01 WHERE col01 IN (SELECT Primary Key FROM tab01); |
index_subquery | unique_subquery와 비슷하나 Primary Key가 아닌 인덱스인 경우 SELECT * FROM tab01 WHERE col01 IN (SELECT key01 FROM tab02); |
range | 특정 범위 내에서 인덱스를 사용하여 원하는 데이터를 추출하는 경우로, 데이터가 방대하지 않다면 단순 SELECT 에서는 나쁘지 않음 |
index | 인덱스를 처음부터 끝까지 찾아서 검색하는 경우로, 일반적으로 인덱스 풀스캔이라고 함 |
all | 테이블을 처음부터 끝까지 검색하는 경우로, 일반적으로 테이블 풀스캔이라고 함 |
possible_keys
목록 중 옵티마이저가 선택한 인덱스
key
의 길이
키 컬럼에 나와 있는 인덱스에서 값을 찾기 위해 선행 테이블의 어떤 컬럼이 사용되었는 지를 나타낸다.
원하는 행을 가져오기 위해 얼마나 많은 행을 읽을지 예측치
구분 | 설명 |
---|---|
using index | 커버링 인덱스라고 하며 인덱스 자료 구조를 이용해서 데이터를 추출 |
using where | where 조건으로 데이터를 추출. type이 ALL 혹은 Indx 타입과 함께 표현되면 성능이 좋지 않다는 의미 |
using filesort | 데이터 정렬이 필요한 경우로 메모리 혹은 디스크상에서의 정렬을 모두 포함. 결과 데이터가 많은 경우 성능에 직접적인 영향을 줌 |
using temporary | 쿼리 처리 시 내부적으로 temporary table이 사용되는 경우를 의미함 |
select_type
dependent.
type은 조회시마다, 외부 테이블에 접근하게 되므로 악영향.uncacheable.
또한 캐시할 수 없으므로 악영향 (ex. rand 함수 사용 등)type
extra
https://nomadlee.com/mysql-explain-sql/
https://cheese10yun.github.io/mysql-explian/#null