Skip to content

Latest commit

 

History

History
555 lines (388 loc) · 24.6 KB

File metadata and controls

555 lines (388 loc) · 24.6 KB

10 실행 계획

10.1 통계 정보

  • MySQL 8.0 부터는 히스토그램 도입
  • MySQL 5.7 버전에서 지원했던 테이블과 인덱스에 대한 개괄적인 정보 + 데이터 칼럼의 분포값 정보 -> 더 정확한 실행계획 선택 가능

10.1.1 테이블 및 인덱스 통계 정보

MySQKL 서버의 통계 정보

  • 휘발성 VS 영구성
    • MySQL 5.6 이전 : 휘발성
      • 메모리에만 관리
      • SHOW INDEX 명령으로만 테이블의 인덱스 칼럼 분포도를 확인할 수 있었음
    • MySQL 5.6 부터 : 영구성
      • InnoDB 스토리지 엔진 사용하는 테이블에 대한 통계 정보를 영구적으로 관리할 수 있음
      • mysql 데이터베이스의 innodb_index_stats 테이블과 innodb_table_stats 테이블로 관리 가능
      • 핵심 : 이제 서버 재시작해도 기존 통계 정보 유지할 수 있게 되었다
      • STATS_PERSISTENT 옵션 : 영구적으로 통계 정보를 보관할지 결정
  • 통계 정보 갱신 (398p)
    • MySQL 5.6 이전 : 자동 갱신
      • 통계 정보가 갱신되면 쿼리 실행 계획 갑자기 달라질 수 있음
      • 통계정보를 바탕으로 실행계획을 수립하기 때문 MySQL 서버가 갑자기 실행 계획을 다르게 설정(예측 불허)
    • MySQL 5.6 부터 : 수동 갱신 가능 + 자동일지도 선택가능
      • 통계 정보 자동 수집 여부 결정 가능 by STATS_AUTO_RECALC 옵션
      • 통계 정보 수집 시, 몇 개의 페이지 샘플링 할 것인지도 설정 가능 by 시스템 변수
        • 갯수 늘리기 -> (+) 더 정확한 통계 정보 수집 가능 -> (-) 수집 시간 길어짐
        • innodb_stats_transient_sample_pages : 8 기본 / 샘플링 분석 후 통계 정보로 활용
        • innodb_stats_persistent_sample_pages : 20 기본 / 샘플링 분석 후 통계 정보 테이블에 저장 + 활용

10.1.2 히스토그램

  • MySQL 5.7 버전까지는
    • 인덱스된 컬럼의 유니크한 값 개수 + 실제 인덱스의 일부 페이지 랜덤 get
  • MySQL 8.0 버전부터는 히스토그램 정보 활용 가능

히스토그램 정보 수집 및 삭제

  • 수집

    • 히스토그램 정보는 컬럼 단위로 관리
    • 수동 수집 - by ANALYZE TABLE ... UPDATE HISTOGRAM
    • (평소에는) 시스템 딕셔너리에 저장
    • (MySQL 서버 실행시) information_schema 데이터베이스, column_statistics 테이블로 로드해서 사용
  • 히스토그램 타입 (401p)

    • 싱글톤 히스토그램 : 칼럼값 개별 레코드 건수 기준
      • 버킷 단위는 칼럼이 가지는 값
      • 유니크한 값의 개수가 적은 경우 사용 -> 레인지 스캔인지 확인하는데 유용하지 않을까
    • 높이 균형 히스토그램 : 컬럼값의 범위를 균등한 개수로 구분해서 관리
      • 버킷 단위는 개수가 균등한 컬럼값의 범위
  • [주의] 403 p 주의 참고 : 히스토그램 수집 시, 풀스캔 조심 (MySQL 8.0.19 미만의 경우)

  • 삭제

    • 쿼리 처리의 성능에 영향 X -> 테이블 데이터를 참조하지 않고 딕셔너리 내용만 삭제하므로
    • 실행 계획에 영향 O -> 실행 계획 수립시 사용하던 히스토그램이 삭제되었으므로
      • MySQL 옵티마이저가 히스토그램 사용하지 않게하는 옵션 사용해서 삭제 시 발생하는 실행 계획 변경에 미리 대비는 가능 (특정 커넥션/쿼리 등 범위를 한정지어서 설정도 가능)
  • 히스토그램의 용도

    • (before) 테이블과 인덱스에 대한 통계정보만으로 실행계획 수립
    • (after) 테이블과 인덱스에 대한 통계정보 + 히스토그램의 분포도 정보
      • (한 번 더 리마인드 > 히스토그램도 추정치임 특정 페이지만을 샘플링한 정보)
      • 실행 계획 정확도 up (405p 쿼리 참고)
      • 조인 순서 결정에 영향 -> 어느 테이블을 먼저 읽어야 조인 횟수를 줄일 수 있는지 정확한 판단 가능 (406p 쿼리 참고)
  • 히스토그램 & 인덱스

    • 인덱스 다이브 - 실제 인덱스의 B-tree를 샘플링해서 본다
      • 인덱스 다이브 통해 사용 가능한 인덱스들을 보고, 조건절에 일치하는 레코드 건수를 대략적으로 파악하는데 사용
  • 인덱스 다이브는 언제 사용?

    • MySQL 8.0 서버부터는 인덱스된 컬럼을 검색 조건으로 사용하는 경우, 히스토그램이 아닌 인덱스 다이브를 활용
    • 즉, 히스토그램은 인덱스되지 않은 칼럼에 대해서만 사용하는 편
  • 인덱스 다이브의 단점?

    • 비용
      • 특히 IN절이 늘어나면 실행 계획 수립만으로도 인덱스 다이브 실행 비용 크다
      • (우디 추측) 인덱스 다이브는 그때그때 만들어지나보다

10.1.3 코스트 모델(Cost Model)

  • 코스트 모델(Cost Model) : 전체 쿼리의 비용을 계산하는데 필요한 단위 작업들의 비용
  • MySQL 5.7 버전까지는
    • MySQL 서버 소스코드에 상수화
    • 하드웨어 따라 달라질 수 있는 점은 고려 X
  • MySQL 5.7 이후부터는
    • 각 단위 작업의 비용을 서버 밖에서 관리 (DB 관리자가 컨트롤 가능)
  • 409 페이지 참고, 코스트 모델의 어떤 단위 작업들에 대해서 비용 설정 가능한지 표기되어있음
    • 작업 비용 높게 산정하면 그만큼 해당 단위 작업들에 쓰는 비용 증가

10.2 실행 계획 확인

10.2.1 실행 계획 출력 포맷

  • MySQL 8.0 이후부터는,
    • 한 번의 EXPLAIN 명령으로 PARTITIONS, EXTEND 다 조회 가능
      • PARTITIONS 과 EXTEND 옵션은 문법에서 안녕~
    • FORMAT 옵션
      • 실행 계획 표시 방법을 선택 가능 - JSON, TREE

10.2.2 쿼리의 실행 시간 확인

  • EXPLAIN ANALYZE 기능
    • 쿼리 실행 계획 확인
    • 실행 단계별로 소요된 시간 정보 확인 가능
    • EXPLAIN과 다르다 : EXPLAIN ANALYZE는 실제 쿼리를 실행하고 사용된 실행계획과 소요된 시간을 보여줌
  • 실행 순서 기준
    • 들여쓰기가 같은 레벨 -> 상단에 위치한 라인 먼저
    • 들여쓰기 다른 레벨 -> 가장 안쪽 라인 먼저
  • EXPLAIN ANALYZE 요소 (공식 문서 참고)
    • actual time : {첫 번째 레코드 검색하는데 걸린 시간}...{마지막 레코드 검색하는데 걸린 시간}
    • rows : 처리한(읽은) 레코드 갯수
    • loops : 작업이 반복된 횟수
  • 414p 예시 함께 잠깐 보기
    • (우디 자문자답) 왜 F가 가장 먼저 실행되는게 아닐까
    • F 구문이 D에 종속적이라서 그런 듯하다

10.3 실행 계획 분석

  • focus on

    • 실행 계획이 어떤 접근 방법을 사용해서 어떤 최적화 수행하는지
    • 어떤 인덱스 사용하는지
  • EXPLAIN 테이블

    • 표의 각 라인(레코드)
      • 쿼리 문장에서 사용된 테이블 (+ 임시테이블도 포함) 출력
    • 실행 순서대로 출력 (UNION, 상관 서브 쿼리 제외)
      • (+ 상관 서브쿼리 : 내부 쿼리의 값이 결정되는데 외부 쿼리에 의존하는 쿼리)
    • 위일 수록 outer 혹은 먼저 접근한 테이블, 아래쪽일 수록 inner 혹은 나중에 접근한 테이블

10.3.1 id 칼럼

  • 단위 SELECT 쿼리별로 부여되는 식별자
    • (+ 단위 쿼리 = SELECT 키워드 단위로 구분한 쿼리)
  • 여러 개의 레코드가 같은 id 가질 수 있다
    • 하나의 SELECT 문장 내 여러 개의 테이블을 조인하면, 조인되는 테이블 개수만큼 실행 계획 레코드가 출력, BUT 같은 id 값 가짐
  • id 칼럼 != 테이블 접근 순서

10.3.2 select_type 칼럼

  • 단위 SELECT 쿼리가 어떤 타입의 쿼리인지 표시됨

Simple

  • UNION이나 서브 쿼리 사용하지 않는 단순 SELECT 쿼리
  • 일반적, 가장 바깥 SELECT 쿼리

Primary

  • UNION이나 서브 쿼리 사용하는 SELECT 쿼리의 실행계획에서 가장 Outer 단위 쿼리

Union

  • UNION으로 결합하는 단위 SELECT 쿼리 중
    • 첫 번째 : DERIVED
    • 첫 번째 이후 단위 쿼리 : UNION
  • (우디) Union 키워드 사용 시, 내부적으로는 임시 테이블 사용하는 구나

Dependent Union

  • 집합을 결합하는 단위 쿼리(UNION, UNION ALL)에서 외부 쿼리에 의해 영향을 받을 경우
  • 상관 서브쿼리일 경우, DEPENDENT 키워드 표시

Union Result

  • UNION의 결과를 담아두는 임시 테이블
  • 단위 쿼리가 아니므로 별도 id 값은 X
  • <union 1, 2> : id 값 1와 2 단위쿼리 결과를 조합
    • MySQL 8.0 이전 : UNION ALL 혹은 UNION 쿼리는 결합 결과를 모두 임시 테이블로 생성
    • MySQL 8.0 이후 : UNION ALL 사용하지 않도록 변경됨 / UNION 여전히 임시 테이블 생성

Subquery

  • 위치에 따른 서브 쿼리 명
    • 중첩된 쿼리 : SELECT 절
    • 서브쿼리 : WHERE 절
    • 파생 테이블 : FROM 절 (= 인라인뷰 = 서브 셀렉트)
  • 반환 값 개수
    • 스칼라 서브쿼리 : 컬럼 하나인 레코드 1건의 값 1개만 반환
    • 로우 서브쿼리 : 컬럼 개수와 상관없이 하나의 레코드만 반환
  • 여기서의 SUBQUERY는 FROM절 이외에서 사용되는 서브쿼리만을 말한다
  • (FROM절에서 사용되는 서브쿼리 = DREIVED 표시)

Dependent Subquery

  • 서브쿼리가 Outer SELECT 쿼리에서 정의된 칼럼을 사용하는 경우
  • 일반적인 서브쿼리보다 처리속도 느리다
    • 외부 쿼리 먼저 수행된 후 내부 쿼리 실행되어야 하므로

Derived

  • MySQL 5.6 이전
    • 서브쿼리 FROM 절 -> 임시 테이블 만든다 -> DERIVED 실행 계획
  • MySQL 5.6 이후
    • FROM 절의 서브쿼리를 외부 쿼리와 통합하는 식의 최적화로 인해 반드시 DERIVED 실행 계획인건 아니게 됨
    • 임시 테이블에서도 인덱스 추가해서 만들 수 있게 됨 (옵티마이저 옵션별로 상이)
  • 서브쿼리 있으면 최대한 조인으로 풀어보자고 또 한 번 다짐..

Dependent Derived

  • MySQL 8.0 이전
    • FROM 절 서브쿼리에서 외부 칼럼 사용 X
  • MySQL 8.0 이후
    • lateral join을 사용하면 가능
  • lateral join 설명 링크

Uncacheable Subquery

  • 캐시를 사용할 수 없는 서브쿼리를 사용하는 경우
  • 원래는 이전의 실행 결과를 그대로 사용할 수 있도록 서브 쿼리 결과를 내부 캐시에 저장
    • 서브쿼리 캐시 != 쿼리 캐시 혹은 파생 테이블
  • 캐시 사용 방법
    • SUBQUERY : 한 번 실행에 대한 결과를 캐시하고, 필요할 때 사용
    • DEPENDENT SUBQUERY : 의존하는 바깥 쿼리의 칼럼 값 단위로 캐시해둔다 (?? 정확한 과정은 잘 모르겠어욥)
  • 캐시 사용하지 못하게 하는 요소들 3가지 (428p)

Uncacheable Union

  • 캐시를 사용할 수 없는 유니언 쿼리 사용하는 경우

Materialized

  • MySQL 5.7 이전
    • outer 테이블 레코드마다 서브 쿼리 실행
  • MySQL 5.7 이후
    • FROM절 혹은 IN(subquery) 형태의 쿼리에 대해서, 서브쿼리 내용을 임시 테이블로 구체화한 뒤 outer 테이블과 조인하는 형태로 최적화
  • Derived 와 동일하게 작동, 서브쿼리의 위치가 다른 것일 뿐임

10.3.3 table 칼럼

  • MySQL 서버의 실행 계획은 테이블 기준
  • <> 표시는 임시 테이블을 의미, 안의 숫자는 단위 SELECT 쿼리 id 값을 지칭

10.3.4 partitions 칼럼

  • MySQL 8.0 버전부터는 EXPLAIN 명령으로 파티션 관련 실행 계획까지 한 번에 확인 가능
  • 파티션 프루닝 : 파티션이 여러 개인 테이블에서 불필요한 파티션을 빼고 쿼리를 수행하도록, 테이블을 골라내는 과정
  • 옵티마이저에서는 쿼리의 조건들을 확인하고, 필요한 파티션만 접근하는 파티션 프루닝으로 쿼리 최적화 시도
    • (+) 대부분 RDB에서 지원하는 파티션은 물리적으로 별도의 공간을 가진다 (그러니, 실행 계획 상으로는 type ALL로 뜰 수 있으니 놀라지 말 것. 우리들이 생각하는 풀스캔 타는거 아님)

10.3.5 type 칼럼

  • 인덱스를 효율적으로 사용하는지 확인할 수 있는 컬럼
  • type 컬럼 == 조인 타입... 이라고 되어있지만 '각 테이블의 접근 방법'이라고 생각해도 좋음

system

  • 레코드가 1건 혹은 아예 존재하지 않는 테이블 참조
  • MyISAM 혹은 MEMORY 테이블에서만 사용

const

  • 프라이머리 키 혹은 유니크 키 칼럼을 이용하는 WHERE 조건절을 가지고 있고 + 반드시 1건을 반환하는 쿼리만을 처리
  • 유니크 인덱스 스캔이라고도 함
  • 일부 칼럼만 조건을 사용할 때는 X -> const가 아닌 ref
  • 옵티마이저의 쿼리 최적화 단계에서 const인 실행 계획은 먼저 쿼리를 실행해서 통째로 상수화한다 (우디 : 그래서 반드시 1건을 반환해야하는군!)

eq_ref

  • 여러 테이블이 조인되는 쿼리 실행 계획에서만 표시
  • 첫 번째 테이블 컬럼값을 두 번째 조인되는 테이블의 PK 혹은 유니크 키 컬럼의 검색조건(조인 조건)으로 사용할 때
    • 두 번재 조인 테이블의 type 컬럼 eq_ref
    • 유니크 키로 검색할 경우 NOT NULL이어야 함
    • 조인에서 두 번째 이후에 읽는 테이블에서 반드시 1건만 존재한다는 보장이 있어야 함

ref

  • 조인의 순서와 관계 없이 사용 + PK 혹은 유니크 키 제약 조건도 X
  • 반드시 1건이라는 보장이 없음 (eq_ref가 더 빠름)
  • 동등 조건으로만 비교하기 때문에 여전히 빠름

const, eq_ref, ref

  • 동등 비교 연산자 사용
  • 쿼리 튜닝시 나오면 좋은 type

fulltext

  • MySQL 서버의 전문 검색 인덱스를 사용해 레코드를 읽는 접근 방식
    • 전문 검색 인덱스는 통계정보 관리 X
    • MATCH (..) AGANIST (..) 구문으로 전문 검색 실행

ref_or_null

  • ref 접근 방법 + null 비교 추가
  • 나쁘지는 않다 (ㅋㅋ)

unique_subquery

  • Where 조건절에서 사용되는 IN(서브 쿼리)를 위한 접근 방식
  • 서브쿼리에서 중복되지 않는 유니크한 값만 반환할 때

index_subquery

  • IN(서브 쿼리) 결과에서 중복된 값이 발생했을 때, 인덱스로 중복된 값을 제거할 수 있음

range

  • 인덱스 레인지 스캔 형태의 접근 방법
  • 범위 형태로 검색하는 경우 적용 (< >, is null, between, in, like)

인덱스를 효율적으로 사용한다

  • const, ref, range 사용한다 (우디 질문 : const는 왜 레인지 스캔일까)

index_merge

  • 2개 이상의 인덱스를 이용 -> 검색 결과 각각 만듦 -> 병합
  • (-) 여러 인덱스 읽어야 함
  • (-) 전문 검색 인덱스 사용 쿼리는 적용 안됨
  • (-) 검색 결과를 모아주는 비용이 필요 (교집합, 합집합, 중복제거 등등)

index

  • 인덱스 풀 스캔
  • 비교 레코드 건수는 테이블 풀 스캔과 동일, BUT 데이터 파일 크기가 다름

ALL

  • 풀 테이블 스캔
  • 가장 비효율적인 방법이지만, '쿼리 튜닝을 한다'는 것이 반드시 인덱스 혹은 테이블 풀 스캔을 사용하지 못하게 하는건 아님 (우디 : 정확하게 이해는 못함)

10.3.6 possible_keys 칼럼

  • 사용될법했던 인덱스의 목록
  • 그냥 무시하자
  • possible_keys 에 적힌 인덱스를 사용했다고 판단하지 말자

10.3.7 key 칼럼

최종 실행 계획에서 사용하는 인덱스

10.3.8 key_len 칼럼

  • 인덱스 각 레코드에서 몇바이트까지 사용했는지 알려줌
  • 다중 칼럼 인덱스 분석에 유용함
  • NULLABLE 칼럼일 경우, NULL 판단 여부를 위해 1 바이트가 추가됨

10.3.9 ref 칼럼

  • equal 비교로 인한 참조조건으로 어떤 테이블의 칼럼이 제공됐는지 표시
  • 상수값이라면 const 가 표시됨
  • func 일 경우 Function 을 통해 연산된 값
  • 사용자가 직접 Function 을 하지 않아도 MySQL 내부적으로 func 일 경우가 있음
    • 대표적으로 숫자 타입을 문자 타입 칼럼으로 join 할 때
    • func 이 되지 않도록, 조인 칼럼을 일치시키는 편이 좋음

10.3.10 rows 칼럼

  • 옵티마이저가 예측한 레코드 건수
  • 따라서 실제 레코드 건수와 일치하지 않는다.

10.3.11 filtered 칼럼

  • WHERE 절을 통해 필터링되고 남은 레코드의 비율
  • MySQL 8.0 부터 히스토그램을 통해 더 정확해짐
  • 필터링이 스토리지 엔진이 아니라 MySQL 엔진에서 이루어진다.
  • 즉 비율이 높으면 버려지는 row 가 많다는 뜻이다.
  • 스토리지에서 디스크를 적게 읽을 수 있도록 최적화가 필요하다.

10.3.12 Extra 칼럼

성능에 관련된 중요한 내용이 표시되므로 알아둘 필요가 있다.

10.3.12.1 const row not found

const 방법으로 읽었지만, 테이블에 레코드가 1건도 존재하지 않으면 표시됨

10.3.12.2 Deleting all rows

DELETE 의 실행계획에서, 모든 레코드를 삭제하는 핸들러 API 를 호출했음을 뜻함

10.3.12.3 Distinct

중복 없이 꼭 필요한 것만 읽어왔다는 것을 뜻함

10.3.12.4 FirstMatch

  • FirstMatch 세미조인 최적화 전략을 사용했다는 것을 뜻함
  • 9.3.1.11절 p.340 그림 참조

10.3.12.5 Full scan on NULL key

  • SQL 표준에서 NULL 은 알수없는 값
  • IN 혹은 NOT IN 연산에서 왼쪽 값이 NULL 인 레코드가 있고, 서브쿼리에 개별적으로 WHERE 가 지정되어 있을 경우
  • Full Table Scan 이 발생해서 심각한 성능 문제가 일어날 수 있음
  • 하지만 왼쪽값이 NULL 이 없다면, Full scan on NULL key 가 표시되어도 걱정안해도 됨

10.3.12.6 Impossible HAVING

HAVING 절의 조건을 만족하는 레코드가 없을 때 표시

10.3.12.7 Impossible WHERE

WHERE 조건이 논리적으로 항상 FALSE 가 되는 경우 표시

10.3.12.8 LooseScan

  • Loose 세미조인 최적화 전략이 사용되었음을 의미
  • 9.3.1.12절 p.342 그림을 참고

10.3.12.9 No matching min/max row

  • MIN, MAX 연산을 할 때 WHERE 을 만족하는 레코드가 없을 때 표시
  • 이때 MIN 과 MAX 는 NULL 을 반환
  • 그 외에는 Impossible WHERE 가 표시됨
  • Impossible... 랑 No matching... 은 잘못된 Extra 가 아니니까 당황하지 말자!
  • 대신에 기획이 문제가 있는 경우가 많으므로 기획자를 혼내자

10.3.12.10 no matching row in const table

const 방법으로 접근할 때 일치하는 레코드가 없으면 표시

10.3.12.11 No matching rows after partition pruning

  • 파티션된 테이블에서 UPDATE, DELETE 시 대상 레코드가 없을 때 표시됨
  • 실제로는 레코드가 없다는 의미가 아니라, 대상 파티션이 없다는 것을 의미

10.3.12.12 No tables used

  • DUAL 테이블이 사용될 때 표시
  • DUAL 은 칼럼과 레코드를 1개씩 가지는 가상의 상수 테이블을 뜻함
  • 사실 모든 쿼리는 FROM 이 필요하지만, MySQL 은 dual 이 존재해서 상수를 쓸 수 있는 것처럼 보임

10.3.12.13 Not exists

  • OUTER JOIN 을 이용해 ANTI-JOIN을 수행할 경우 표시
  • ANTI-JOIN: INNER JOIN 을 했을 때 나오지 않는 결과를 가져오는 걸 뜻함
  • 옵티마이저가 최적화를 잘했다는 것을 의미

10.3.12.14 Plan isn't ready yet

  • MySQL 8.0 은 실행 중인 쿼리의 실행 계획을 살펴볼 수 있음
  • 아직 실행 계획을 수립 못했다는 것을 뜻함

10.3.12.15 Range checked for each record(index map: N)

  • 레코드마다 인덱스 레인지 스캔을 체크할 때 표시
  • type 칼럼에 ALL 이라고 표시되어도 당황치 말자, 후보 인덱스가 별 도움이 안되어서 풀 테이블 스캔을 한 것이다.
  • 각 레코드 단위로 여러 후보 인덱스 중에서 실제 어떤 인덱스가 사용됐는지는 알 수 없다.

10.3.12.16 Recursive

  • WITH RECURSIVE 문법을 사용할 경우 표시
  • MySQL 8.0 부터 CTE(Common Table Expression) 이 도입됨

10.3.12.17 Rematerialize

  • MySQL 8.0 부터 LATERAL JOIN 도입
  • LATERAL JOIN 시, 레코드별로 서브쿼리 실행한 결과를 임시 테이블에 저장함
  • 임시 테이블에 저장하는 과정을 Rematerializing 이라고 함
  • 책 2권 11.4.7.6 절에 자세히 나온다고 함

10.3.12.18 Select tables optimized away

  • MIN, MAX, GROUP BY 시
  • 인덱스를 오름차순 또는 내림차순으로 1건만 읽을경우 적용되는 최적화

10.3.12.19 Start temporary, End temporary

  • Duplicate Weed-out 세미 조인 최적화를 할 경우 표시
  • 9.3.1.14 절 p346 참고

10.3.12.20 unique row not found

  • 유니크 칼럼으로 아우터 조인을 할 때, 아우터 테이블에 일치하는 레코드가 존재하지 않을 때 표시

10.3.12.21 Using filesort

  • ORDER BY 처리가 인덱스를 사용하지 못할 때 표시
  • 많은 부하를 일으키므로 튜닝이 필요
  • 책 2권 11.4.9 에서 자세히 다룰 예정

10.3.12.22 Using index(커버링 인덱스)

  • 데이터 파일을 전혀 읽지 않고, 인덱스만 읽어서 쿼리를 모두 처리할 수 있을 때 표시
  • 이렇게 인덱스만으로 쿼리를 실행하는 것을 Covering Index 라고 함
  • 매우 빠르다는 것을 뜻하니깐, 표시되면 행복해하면 될 것 같다.
  • type 칼럼의 index 는 풀 스캔을 의미하므로 헷갈리지 말자

10.3.12.23 Using index condition

  • Index condition pushdown 최적화를 할 경우 표시
  • 9.3.1.3절 p.325 참조

10.3.12.24 Using index for group-by

  • GROUP BY 처리에 인덱스를 이용했음을 뜻함
  • GROUP BY 처리시 인덱스 읽는 방법을 Loose Index Scan 이라고 함
10.3.12.24.1 타이트 인덱스 스캔을 통한 GROUP BY 처리
  • AVG, SUM, COUNT 처럼 모든 인덱스를 다 읽는 것은 Loose 하지 않아서 그냥 Using Index 만 표시됨
10.3.12.24.2 루스 인덱스 스캔을 통한 GROUP BY 처리
  • MIN, MAX 처럼 모든 레코드를 다 읽을 필요가 없을 경우 Loose Index Scan 이 적용됨
  • 그럴 경우 Using Index for group-by 가 표시됨
  • GROUP BY 뿐만 아니라 WHERE 절에서 사용하는 인덱스에 따라, GROUP BY 시 인덱스를 안 탈 수도 있음
    • WHERE 조건절이 없는 경우
      • Loose Index Scan 을 사용할 조건을 갖추면 발동
    • WHERE 조건절이 있지만, 검색을 위해 인덱스를 사용하지 못한 경우
      • 발동안함. Tight Index Scan 발동
    • WHERE 조건절이 있으며, 검색을 위해 인해 인덱스를 사용하는 경우
      • WHERE 과 GROUP BY 가 똑같은 인덱스를 사용할 수 있어야 Loose Index Scan 발동

10.3.12.25 Using index for skip scan

  • Index Skip Scan 최적화를 할 경우 표시
  • 8.3.4.4 절 p.238 참고

10.3.12.26 Using join buffer

  • join 시 Driven 테이블의 인덱스를 탈 수 없다면, Block Nested Loop Join 혹은 Hash Join 이 사용됨
  • 그럴 경우 Join Buffer 가 사용됨
    • Using join buffer(Block Nested Loop)
    • Using join buffer(Batched Key Access)
    • Using join buffer(hash join)

10.3.12.27 Using MRR

  • MRR(Multi Range Read) 최적화를 할 경우 표시
  • MySQL 엔진이 스토리지 엔진에게 넘겨주는 키 값을 정렬해서 최소한의 페이지 접근이 일어나도록 함
  • 디스크 접근을 최소화 하는 최적화 기법
  • 자세한 내용은 9.3.1.1 p.320 참조

10.3.12.28 Using sort_union, Using union, Using intersect

index_merge 시, 2개 이상의 인덱스가 동시에 사용될 경우 표시
이산수학 때 (AND, INTERSECT), (OR, UNION) 이 어떻게 연결되는지 배우므로 설명은 생략한다.

  • Using intersect
    • 인덱스들이 AND 조건으로 연결됨
  • Using union
    • 인덱스들이 OR 조건으로 연결됨
  • Using sort_union
    • OR 연결이 많을 경우, PK 먼저 읽어서 정렬 후 병합했음을 뜻함

10.3.12.29 Using temporary

  • 임시 테이블을 사용할 때 표시
  • 임시 테이블이 메모리에 있는지, 디스크에 있는지는 모름
  • Using temporary 가 표시 안되도 임시 테이블을 사용했을 수도 있음

10.3.12.30 Using where

  • 스토리지 엔진이 아니라, MySQL 엔진에서 필터링이 있었음을 뜻함
  • 만약 filtered 칼럼의 값이 높다면, 스토리지 엔진에서 가져온 많은 데이터가 쓸모 없었다는 것을 뜻함
  • filtered 칼럼의 값이 높다면, 디스크를 더 적게 읽도록 최적화가 필요함

10.3.12.31 Zero limit

  • 쿼리 마지막에 LIMIT 0 을 하면 결과의 메타데이터만 읽을 수 있음