by-nc-sa     개발자, DBA가 함께 만들어가는 구루비 지식창고!

04. 실행 계획 분석 PART1 (48p, 146 ~ 194)




실행계획 분석 PART1

  • 개요
    • 쿼리 실행 절차
      구분 단계 실행 주체 결과물
      1 SQL 파싱 SQL 파서(MariaDB 엔진) SQL 파스 트리
      2 최적화 및 실행 계획 수립 옵티마이저(MariaDB 엔진) 실행 계획
      3 SQL 실행 스토리지 엔진 + MariaDB 엔진 쿼리 결과값
    • 옵티마이저의 종류
      규칙 기반 최적화
      (RBO:Rule-based optimizer)
      옵티마이저에 내장된 우선순위에 따라 실행 계획을 수립
      비용 기반 최적화
      (CBO:Cost-based optimizer)
      부하 정보와 통계 정보를 이용해 각 실행 계획별 비용을 산출하여 최소 비용의 실행 계획을 선택
    • MariaDB 10.0의 통계 정보
      1. MariaDB 10.0부터 통합 통계 정보 관리 기능을 제공
      2. 인덱스 컬럼 외 컬럼의 통계 정보 관리 가능
      3. 통계 정보를 영구적으로 사용 가능: 통계 정보를 별도로 백업해 복구해서 사용할 수 있음
      4. 관리자가 직접 통계 정보 변경 가능
      5. 통합 통계 테이블
        table_stat 컬럼 의미
          db_name 대상 테이블이 속한 데이터베이스 명
          table_name 대상 테이블의 이름
          cardianlity 테이블의 레코드 건수
        column_stat 컬럼 의미
          db_name 대상 테이블이 속한 데이터베이스 명
          table_name 대상 테이블의 이름
          column_name 대상 컬럼 이름
          min_value 해당 컬럼의 최소값(정수 타입도 문자열 포맷으로 저장)
          max_value 해당 컬럼의 최대값(정수 타입도 문자열 포맷으로 저장)
          nulls_ratio NULL 값의 비율(0:NULL 없음, 0.5:NULL값을 가진 레코드가 50%, 1: 모든 레코드가 NULL)
          avg_length 컬럼 값의 평균 바이트 수
          avg_frequency 중복된 값을 가진 평균 레코드의 수(1:중복된 값 없음)
        index_stat 컬럼 의미
          db_name 대상 테이블이 속한 데이터베이스 명
          table_name 대상 테이블의 이름
          index_name 대상 인덱스의 이름
          prefix_arity 인덱스 컬럼 순번
          avg_frequency 중복된 값을 가진 평균 레코드의 수(1:중복된 값 없음)
      6. 통계 파라미터
        파라미터 내용
        use_stat_tables never MySQL 5.6의 통계 정보 관리 방식과 동일, 통합 통계 테이블에는 통계를 수집하지 않음
        use_stat_tables complementary 각 스토리지 엔진이 제공하는 통계정보를 우선적으로 사용하되 스토리지 엔진이 제공하는 정보가 부족하거나 없는 경우에는 MariaDB의 통합 정보가 사용됨
        use_stat_tables preferably 각 스토리지 엔진별로 관리되는 통계 정보보다 MariaDB의 통합 통계 정보를 우선해서 사용
        create table tabl_recalc as select * from employees;
        
        insert into tabl_recalc select * from employees;
        
        MariaDB [(none)]> show global variables like 'innodb_stats_auto_recalc';
        +--------------------------+-------+
        | Variable_name            | Value |
        +--------------------------+-------+
        | innodb_stats_auto_recalc | ON    |
        +--------------------------+-------+
        1 row in set (0.00 sec)
        
        MariaDB [employees]> select * from mysql.table_stats where table_name='tabl_recalc';
        Empty set (0.00 sec)
        
        MariaDB [employees]> select * from mysql.innodb_table_stats where table_name='tabl_recalc';
        +---------------+-------------+---------------------+--------+----------------------+--------------------------+
        | database_name | table_name  | last_update         | n_rows | clustered_index_size | sum_of_other_index_sizes |
        +---------------+-------------+---------------------+--------+----------------------+--------------------------+
        | employees     | tabl_recalc | 2017-04-14 21:33:55 | 299439 |                 1057 |                        0 |
        +---------------+-------------+---------------------+--------+----------------------+--------------------------+
        1 row in set (0.00 sec)
        
        MariaDB [employees]> show global variables like 'use_stat_tables';
        +-----------------+-------+
        | Variable_name   | Value |
        +-----------------+-------+
        | use_stat_tables | NEVER |
        +-----------------+-------+
        1 row in set (0.00 sec)
        
        MariaDB [employees]> analyze table tabl_recalc;
        +-----------------------+---------+----------+----------+
        | Table                 | Op      | Msg_type | Msg_text |
        +-----------------------+---------+----------+----------+
        | employees.tabl_recalc | analyze | status   | OK       |
        +-----------------------+---------+----------+----------+
        1 row in set (0.01 sec)
        
        MariaDB [employees]> select * from mysql.table_stats where table_name='tabl_recalc';
        Empty set (0.00 sec)
        
        MariaDB [employees]> SET SESSION use_stat_tables='COMPLEMENTARY';
        Query OK, 0 rows affected (0.00 sec)
        
        MariaDB [employees]> analyze table tabl_recalc;
        +-----------------------+---------+----------+-----------------------------------------+
        | Table                 | Op      | Msg_type | Msg_text                                |
        +-----------------------+---------+----------+-----------------------------------------+
        | employees.tabl_recalc | analyze | status   | Engine-independent statistics collected |
        | employees.tabl_recalc | analyze | status   | OK                                      |
        +-----------------------+---------+----------+-----------------------------------------+
        2 rows in set (0.54 sec)
        
        MariaDB [employees]> select * from mysql.table_stats where table_name='tabl_recalc';
        +-----------+-------------+-------------+
        | db_name   | table_name  | cardinality |
        +-----------+-------------+-------------+
        | employees | tabl_recalc |      300024 |
        +-----------+-------------+-------------+
        1 row in set (0.00 sec)
        
        통계 수집 시 주의 사항

        ANALYZE TABLE 명령이 실행되면 테이블을 풀 스캔하거나 인덱스 풀 스캔하여 통계 수집
        마스터와 슬레이브 구조라면 슬레이브에서 통계 정보를 수집하여 마스터에 복사

      7. 통계 생성 구문
        tbl 테이블, col1과 col2 컬럼, idx1과 idx2 인덱스에 대해서만 통계 정보 수집
        analyze table tbl persistent for columns (col1, col2) indexes (idx1, idx2);
        tbl 테이블, col1과 col2 컬럼에 대해서만 통계 수집
        analyze table tbl persistent for columns (col1, col2) indexes ();
        tbl 테이블, idx1, idx2 인덱스에 대해서만 통계 수집
        analyze table tbl persistent for columns () indexes (idx1, idx2);
        tbl 테이블에 대해서만 통계 수집
        analyze table tbl persistent for columns () indexes ();
        테이블, 모든 컬럼, 모든 인덱스의 통계 수집(=analyze table tbl; )
        analyze table tbl persistent for all;
    • 히스토그램 통계 정보
      1. 히스토그램: 컬럼 값의 분포도를 분석할 수 있는 통계 정보
      2. Height-Balanced Histogram 알고리즘 사용
        MariaDB [employees]> desc mysql.column_stats;
        +---------------+-----------------------------------------+------+-----+---------+-------+
        | Field         | Type                                    | Null | Key | Default | Extra |
        +---------------+-----------------------------------------+------+-----+---------+-------+
        | db_name       | varchar(64)                             | NO   | PRI | NULL    |       |
        | table_name    | varchar(64)                             | NO   | PRI | NULL    |       |
        | column_name   | varchar(64)                             | NO   | PRI | NULL    |       |
        | min_value     | varbinary(255)                          | YES  |     | NULL    |       |
        | max_value     | varbinary(255)                          | YES  |     | NULL    |       |
        | nulls_ratio   | decimal(12,4)                           | YES  |     | NULL    |       |
        | avg_length    | decimal(12,4)                           | YES  |     | NULL    |       |
        | avg_frequency | decimal(12,4)                           | YES  |     | NULL    |       |
        | hist_size     | tinyint(3) unsigned                     | YES  |     | NULL    |       |
        | hist_type     | enum('SINGLE_PREC_HB','DOUBLE_PREC_HB') | YES  |     | NULL    |       |
        | histogram     | varbinary(255)                          | YES  |     | NULL    |       |
        +---------------+-----------------------------------------+------+-----+---------+-------+
        11 rows in set (0.00 sec)
        
        --MariaDB에서 히스토그램 사용
        MariaDB [employees]> set histogram_size=20;
        Query OK, 0 rows affected (0.00 sec)
        
        MariaDB [employees]> set use_stat_tables='preferably';
        Query OK, 0 rows affected (0.00 sec)
        
        MariaDB [employees]> set histogram_type='double_prec_hb';
        Query OK, 0 rows affected (0.00 sec)
        
        MariaDB [employees]> analyze table salaries;
        +--------------------+---------+----------+-----------------------------------------+
        | Table              | Op      | Msg_type | Msg_text                                |
        +--------------------+---------+----------+-----------------------------------------+
        | employees.salaries | analyze | status   | Engine-independent statistics collected |
        | employees.salaries | analyze | status   | OK                                      |
        +--------------------+---------+----------+-----------------------------------------+
        2 rows in set (8.28 sec)
        
        MariaDB [employees]> select table_name, min_value, max_value, hist_size, hist_type,
            -> decode_histogram(hist_type, histogram) as histogram
            -> from mysql.column_stats
            -> where table_name='salaries' and column_name='salary'\G
        *************************** 1. row ***************************
        table_name: salaries
         min_value: 38623
         max_value: 158220
         hist_size: 20
         hist_type: DOUBLE_PREC_HB
         histogram: 0.04030,0.03436,0.03273,0.03198,0.03232,0.03375,0.03688,0.04285,0.05443,0.07974,0.58065    <<< 버킷최대값 / (최대값-최소값) * 216 (single_prec_hb:28)
        1 row in set (0.00 sec)
        
        MariaDB [employees]> set histogram_size=100;
        Query OK, 0 rows affected (0.00 sec)
        
        MariaDB [employees]> set use_stat_tables='preferably';
        Query OK, 0 rows affected (0.00 sec)
        
        MariaDB [employees]> set histogram_type='double_prec_hb';
        Query OK, 0 rows affected (0.00 sec)
        
        MariaDB [employees]> analyze table salaries;
        +--------------------+---------+----------+-----------------------------------------+
        | Table              | Op      | Msg_type | Msg_text                                |
        +--------------------+---------+----------+-----------------------------------------+
        | employees.salaries | analyze | status   | Engine-independent statistics collected |
        | employees.salaries | analyze | status   | OK                                      |
        +--------------------+---------+----------+-----------------------------------------+
        2 rows in set (7.94 sec)
        
        MariaDB [employees]> set optimizer_use_condition_selectivity=4;
        Query OK, 0 rows affected (0.00 sec)
        
        MariaDB [employees]> explain extended select * from salaries where to_date <= '1989-03-01';
        +------+-------------+----------+------+---------------+------+---------+------+---------+----------+-------------+
        | id   | select_type | table    | type | possible_keys | key  | key_len | ref  | rows    | filtered | Extra       |
        +------+-------------+----------+------+---------------+------+---------+------+---------+----------+-------------+
        |    1 | SIMPLE      | salaries | ALL  | NULL          | NULL | NULL    | NULL | 2844047 |     5.88 | Using where |
        +------+-------------+----------+------+---------------+------+---------+------+---------+----------+-------------+
        1 row in set, 1 warning (0.00 sec)
        
        MariaDB [employees]> select count(*), (2844047*0.0588) as expected_value from salaries where to_date <= '1989-03-01';
        +----------+----------------+
        | count(*) | expected_value |
        +----------+----------------+
        |   125536 |    167229.9636 |
        +----------+----------------+
        1 row in set (2.40 sec)
        
        MariaDB [employees]> set histogram_size=200;
        Query OK, 0 rows affected (0.00 sec)
        
        MariaDB [employees]> analyze table salaries;
        +--------------------+---------+----------+-----------------------------------------+
        | Table              | Op      | Msg_type | Msg_text                                |
        +--------------------+---------+----------+-----------------------------------------+
        | employees.salaries | analyze | status   | Engine-independent statistics collected |
        | employees.salaries | analyze | status   | OK                                      |
        +--------------------+---------+----------+-----------------------------------------+
        2 rows in set (9.70 sec)
        
        MariaDB [employees]> explain extended
            -> select * from salaries where to_date <= '1989-03-01';
        +------+-------------+----------+------+---------------+------+---------+------+---------+----------+-------------+
        | id   | select_type | table    | type | possible_keys | key  | key_len | ref  | rows    | filtered | Extra       |
        +------+-------------+----------+------+---------------+------+---------+------+---------+----------+-------------+
        |    1 | SIMPLE      | salaries | ALL  | NULL          | NULL | NULL    | NULL | 2844047 |     4.95 | Using where |
        +------+-------------+----------+------+---------------+------+---------+------+---------+----------+-------------+
        1 row in set, 1 warning (0.00 sec)
        
        MariaDB [employees]> select count(*), (2844047*0.0495) as expected_value from salaries where to_date <= '1989-03-01';
        +----------+----------------+
        | count(*) | expected_value |
        +----------+----------------+
        |   125536 |    140780.3265 |
        +----------+----------------+
        1 row in set (2.83 sec)
        
    • 조인 옵티마이저 옵션
      1. Exhaustive 검색: from절에 명시된 모든 테이블 조합에 대해서 실행 계획의 비용을 계산하여 최적의 조합 선택
      2. Heuristic 검색(Greedy 검색)
        구분 내용
        1 전체 N개의 테이블 중에서 optimizer_search_depth 시스템 설정 변수에 정의된 개수의 테이블로 가능한 조인 조합을 생성
        2 1번에서 생성된 조인 조합 중에서 최소 비용의 실행 계획 하나를 선정
        3 2번에서 선정된 실행 계획의 첫 번째 테이블을 "부분 실행 계획"의 첫번째 테이블로 선정
        4 전체 N-1개의 테이블 중에서(3번에서 선택된 테이블 제외) optimizer_search_depth 시스템 변수에 정의된 개수의 테이블로 가능한 조인 조합을 생성
        5 4번에서 생성된 조인 조합들을 하나씩 3번에서 생성된 "부분 실행 계획"에 대입해서 실행 비용을 계산
        6 5번의 비용 계산 결과, 가장 비용이 낮은 실행 계획을 골라서 그 중 두 번째 테이블을 3번에서 생성된 "부분 실행 계획"의 두 번째 테이블로 선정
        7 남은 테이블이 모두 없어질 때까지 4~6번까지의 과정을 반복 실행하면서 "부분 실행 계획"에 테이블의 조인 순서를 기록
        8 최종적으로 "부분 실행 계획"이 테이블의 조인 순서로 결정
      • optimizer_search_depth의 default 값: 64
        MariaDB [employees]> set session optimizer_prune_level=1;
        Query OK, 0 rows affected (0.00 sec)
        
        MariaDB [employees]> set session optimizer_search_depth=5;
        Query OK, 0 rows affected (0.00 sec)
        
        MariaDB [employees]> select * from tab01,tab02,tab03,tab04,tab05,tab06,tab07,tab08,tab09,tab10, tab11,tab12,tab13,tab14,tab15,tab16,tab17,tab18,tab19,tab20, tab21,tab22,tab23,tab24,tab25,tab26,tab27,tab28,tab29,tab30 where tab01.fd1=tab02.fd1 and tab02.fd1=tab03.fd2 and tab03.fd1=tab04.fd1 and tab04.fd2=tab05.fd2 and tab05.fd2=tab06.fd1 and tab06.fd2=tab07.fd2 and tab07.fd1=tab08.fd1 and tab08.fd1=tab09.fd2 and tab09.fd1=tab10.fd1 and tab10.fd2=tab11.fd2 and tab11.fd2=tab12.fd1 and tab12.fd2=tab13.fd2 and tab13.fd1=tab14.fd1 and tab14.fd1=tab15.fd2 and tab15.fd1=tab16.fd1 and tab16.fd2=tab17.fd2 and tab17.fd2=tab18.fd1 and tab18.fd2=tab19.fd2 and tab19.fd1=tab20.fd1 and tab20.fd1=tab21.fd2 and tab21.fd1=tab22.fd1 and tab22.fd2=tab23.fd2 and tab23.fd2=tab24.fd1 and tab24.fd2=tab25.fd2 and tab25.fd1=tab26.fd1 and tab26.fd1=tab27.fd2 and tab27.fd1=tab28.fd1 and tab28.fd2=tab29.fd2 and tab29.fd2=tab30.fd1;
        (((결과 생략)))
        2000 rows in set (0.09 sec)
        
        MariaDB [employees]> set session optimizer_search_depth=64;
        Query OK, 0 rows affected, 2 warnings (0.00 sec)
        
        MariaDB [employees]> reset query cache;
        Query OK, 0 rows affected (0.00 sec)
        
        MariaDB [employees]> select * from tab01,tab02,tab03,tab04,tab05,tab06,tab07,tab08,tab09,tab10, tab11,tab12,tab13,tab14,tab15,tab16,tab17,tab18,tab19,tab20, tab21,tab22,tab23,tab24,tab25,tab26,tab27,tab28,tab29,tab30 where tab01.fd1=tab02.fd1 and tab02.fd1=tab03.fd2 and tab03.fd1=tab04.fd1 and tab04.fd2=tab05.fd2 and tab05.fd2=tab06.fd1 and tab06.fd2=tab07.fd2 and tab07.fd1=tab08.fd1 and tab08.fd1=tab09.fd2 and tab09.fd1=tab10.fd1 and tab10.fd2=tab11.fd2 and tab11.fd2=tab12.fd1 and tab12.fd2=tab13.fd2 and tab13.fd1=tab14.fd1 and tab14.fd1=tab15.fd2 and tab15.fd1=tab16.fd1 and tab16.fd2=tab17.fd2 and tab17.fd2=tab18.fd1 and tab18.fd2=tab19.fd2 and tab19.fd1=tab20.fd1 and tab20.fd1=tab21.fd2 and tab21.fd1=tab22.fd1 and tab22.fd2=tab23.fd2 and tab23.fd2=tab24.fd1 and tab24.fd2=tab25.fd2 and tab25.fd1=tab26.fd1 and tab26.fd1=tab27.fd2 and tab27.fd1=tab28.fd1 and tab28.fd2=tab29.fd2 and tab29.fd2=tab30.fd1;
        (((결과 생략)))
        2000 rows in set (0.10 sec)
        
  • 실행 계획 분석
    MariaDB [employees]> explain
        -> select e.emp_no, e.first_name, s.from_date, s.salary
        -> from employees e, salaries s
        -> where e.emp_no = s.emp_no
        -> limit 10;
    +------+-------------+-------+-------+---------------+--------------+---------+--------------------+--------+-------------+
    | id   | select_type | table | type  | possible_keys | key          | key_len | ref                | rows   | Extra       |
    +------+-------------+-------+-------+---------------+--------------+---------+--------------------+--------+-------------+
    |    1 | SIMPLE      | e     | index | PRIMARY       | ix_firstname | 16      | NULL               | 299335 | Using index |
    |    1 | SIMPLE      | s     | ref   | PRIMARY       | PRIMARY      | 4       | employees.e.emp_no |      4 |             |
    +------+-------------+-------+-------+---------------+--------------+---------+--------------------+--------+-------------+
    2 rows in set (0.00 sec)
    
    1. 레코드는 쿼리 문장에서 사용된 테이블의 개수만큼 출력(임시테이블 포함)
    2. 실행 순서는 위에서 아래로 순서대로 표시(union이나 상관 서브 쿼리와 같은 경우 순서대로 표시되지 않을 수 있음)
    3. id 컬럼의 값이 작을 수록 쿼리의 outer부분이거나 먼저 접근한 테이블, id 컬럼의 값이 클수록 쿼리의 inner부분 또는 나중에 접근한 테이블
    • id 컬럼: 단위 select 쿼리별로 부여되는 식별자
      MariaDB [employees]> explain
          -> select
          -> ((select count(*) from employees) + (select count(*) from departments)) as total_count;
      +------+-------------+-------------+-------+---------------+-------------+---------+------+--------+----------------+
      | id   | select_type | table       | type  | possible_keys | key         | key_len | ref  | rows   | Extra          |
      +------+-------------+-------------+-------+---------------+-------------+---------+------+--------+----------------+
      |    1 | PRIMARY     | NULL        | NULL  | NULL          | NULL        | NULL    | NULL |   NULL | No tables used |
      |    3 | SUBQUERY    | departments | index | NULL          | PRIMARY     | 4       | NULL |      9 | Using index    |
      |    2 | SUBQUERY    | employees   | index | NULL          | ix_hiredate | 3       | NULL | 299335 | Using index    |
      +------+-------------+-------------+-------+---------------+-------------+---------+------+--------+----------------+
      3 rows in set (0.00 sec)
      
    • select_type 컬럼
      SIMPLE union이나 서브 쿼리를 사용하지 않는 단순한 select 쿼리, 실행계획에서 SIMPLE은 하나만 존재하며 일반적으로 제일 바깥 select쿼리가 SIMPLE로 표시
      PRIMARY union이나 서브 쿼리를 가지는 select 쿼리의 실행 계획에서 가장 바깥쪽(outer)에 있는 단위 쿼리, 실행계획에서 하나만 존재하며 일반적으로 제일 바깥 select쿼리가 PRIMARY로 표시
      UNION union으로 결합하는 단위 select쿼리 가운데 첫 번째를 제외한 두 번째 이후 단위 select 쿼리
      DEPENDENT UNION union이나 union all로 결합된 단위 쿼리가 외부의 의해 영향을 받는 쿼리
      UNION RESULT union 결과 테이블을 의미, id 값이 부여되지 않음
      SUBQUERY from절 이외에서 사용되는 서브 쿼리만을 의미
      DEPENDENT SUBQUERY 서브 쿼리가 바깥쪽(outer) select 쿼리에서 정의된 컬럼을 사용하는 경우
      DERIVED 단위 select쿼리의 실행 결과를 메모리나 디스크에 임시 테이블을 생성하는 것을 의미, 서브 쿼리가 from절에 사용된 경우
      UNCACHEABLE SUBQUERY 서브 쿼리 결과를 내부적인 캐시 공간에 저장되지 못하는 경우
      1. 사용자 변수가 서브 쿼리에 사용된 경우
      2. not-deterministic 속성의 스토어드 루틴이 서브 쿼리 내에 사용된 경우
      3. UUID()나 RAND()와 같이 결과값이 호출될 때마다 달라지는 함수가 서브 쿼리에 사용된 경우
      UNCACHEABLE UNION union 쿼리 결과가 내부적인 캐시 공간에 저장되지 못하는 경우
      MATERIALIZED 서브 쿼리의 내용을 임시 테이블로 구체화(materialization)하는 경우
      INSERT insert문의 실행계획
      
      --UNION
      MariaDB [employees]> explain
          -> select tb.* from (
          -> (select emp_no from employees e1 limit 10)
          -> union all
          -> (select emp_no from employees e2 limit 10)
          -> union all
          -> (select emp_no from employees e3 limit 10)
          -> ) tb;
      +------+-------------+------------+-------+---------------+-------------+---------+------+--------+-------------+
      | id   | select_type | table      | type  | possible_keys | key         | key_len | ref  | rows   | Extra       |
      +------+-------------+------------+-------+---------------+-------------+---------+------+--------+-------------+
      |    1 | PRIMARY     | <derived2> | ALL   | NULL          | NULL        | NULL    | NULL |     30 |             |
      |    2 | DERIVED     | e1         | index | NULL          | ix_hiredate | 3       | NULL | 299335 | Using index |
      |    3 | UNION       | e2         | index | NULL          | ix_hiredate | 3       | NULL | 299335 | Using index |
      |    4 | UNION       | e3         | index | NULL          | ix_hiredate | 3       | NULL | 299335 | Using index |
      +------+-------------+------------+-------+---------------+-------------+---------+------+--------+-------------+
      4 rows in set (0.00 sec)
      
      --DEPENDENT UNION & UNION RESULT
      MariaDB [employees]> explain
          -> select *
          -> from employees e1
          -> where e1.emp_no in (
          -> select e2.emp_no from employees e2 where e2.first_name='Matt'
          -> union
          -> select e3.emp_no from employees e3 where e3.first_name='Matt'
          -> );
      +------+--------------------+------------+--------+----------------------+---------+---------+------+--------+-------------+
      | id   | select_type        | table      | type   | possible_keys        | key     | key_len | ref  | rows   | Extra       |
      +------+--------------------+------------+--------+----------------------+---------+---------+------+--------+-------------+
      |    1 | PRIMARY            | e1         | ALL    | NULL                 | NULL    | NULL    | NULL | 299335 | Using where |
      |    2 | DEPENDENT SUBQUERY | e2         | eq_ref | PRIMARY,ix_firstname | PRIMARY | 4       | func |      1 | Using where |
      |    3 | DEPENDENT UNION    | e3         | eq_ref | PRIMARY,ix_firstname | PRIMARY | 4       | func |      1 | Using where |
      | NULL | UNION RESULT       | <union2,3> | ALL    | NULL                 | NULL    | NULL    | NULL |   NULL |             |
      +------+--------------------+------------+--------+----------------------+---------+---------+------+--------+-------------+
      4 rows in set (0.00 sec)
      
      --DEPENDENT SUBQUERY
      MariaDB [employees]> explain
          -> select e.first_name,
          -> (select count(*)
          -> from dept_emp de, dept_manager dm
          -> where dm.dept_no=de.dept_no and de.emp_no=e.emp_no) as cnt
          -> from employees e
          -> where e.first_name='Matt';
      +------+--------------------+-------+------+---------------------------+-------------------+---------+----------------------+------+--------------------------+
      | id   | select_type        | table | type | possible_keys             | key               | key_len | ref                  | rows | Extra                    |
      +------+--------------------+-------+------+---------------------------+-------------------+---------+----------------------+------+--------------------------+
      |    1 | PRIMARY            | e     | ref  | ix_firstname              | ix_firstname      | 16      | const                |  233 | Using where; Using index |
      |    2 | DEPENDENT SUBQUERY | de    | ref  | PRIMARY,ix_empno_fromdate | ix_empno_fromdate | 4       | employees.e.emp_no   |    1 | Using index              |
      |    2 | DEPENDENT SUBQUERY | dm    | ref  | PRIMARY                   | PRIMARY           | 4       | employees.de.dept_no |    1 | Using index              |
      +------+--------------------+-------+------+---------------------------+-------------------+---------+----------------------+------+--------------------------+
      3 rows in set (0.00 sec)
      
      --DERIVED
      MariaDB [employees]> explain
          -> select *
          -> from (select de.emp_no from dept_emp de group by de.emp_no) tb,
          -> employees e
          -> where e.emp_no=tb.emp_no;
      +------+-------------+------------+--------+---------------+-------------------+---------+-----------+--------+-------------+
      | id   | select_type | table      | type   | possible_keys | key               | key_len | ref       | rows   | Extra       |
      +------+-------------+------------+--------+---------------+-------------------+---------+-----------+--------+-------------+
      |    1 | PRIMARY     | <derived2> | ALL    | NULL          | NULL              | NULL    | NULL      | 331570 |             |
      |    1 | PRIMARY     | e          | eq_ref | PRIMARY       | PRIMARY           | 4       | tb.emp_no |      1 |             |
      |    2 | DERIVED     | de         | index  | NULL          | ix_empno_fromdate | 7       | NULL      | 331570 | Using index |
      +------+-------------+------------+--------+---------------+-------------------+---------+-----------+--------+-------------+
      3 rows in set (0.00 sec)
      
      --UNCACHEABLE SUBQUERY
      MariaDB [employees]> explain
          -> select *
          -> from employees e
          -> where e.emp_no = (
          -> select @status from dept_emp de where de.dept_no='d005'
          -> );
      +------+----------------------+-------+-------+---------------+---------+---------+-------+--------+--------------------------+
      | id   | select_type          | table | type  | possible_keys | key     | key_len | ref   | rows   | Extra                    |
      +------+----------------------+-------+-------+---------------+---------+---------+-------+--------+--------------------------+
      |    1 | PRIMARY              | e     | const | PRIMARY       | PRIMARY | 4       | const |      1 | Using where              |
      |    2 | UNCACHEABLE SUBQUERY | de    | ref   | PRIMARY       | PRIMARY | 4       | const | 165785 | Using where; Using index |
      +------+----------------------+-------+-------+---------------+---------+---------+-------+--------+--------------------------+
      2 rows in set (0.01 sec)
      
      MariaDB [employees]> explain
          -> select *
          -> from employees e
          -> where e.emp_no in (select emp_no from salaries where salary between 100 and 1000);
      +------+--------------+-------------+--------+-------------------+-----------+---------+---------------------------+------+--------------------------+
      | id   | select_type  | table       | type   | possible_keys     | key       | key_len | ref                       | rows | Extra                    |
      +------+--------------+-------------+--------+-------------------+-----------+---------+---------------------------+------+--------------------------+
      |    1 | PRIMARY      | <subquery2> | ALL    | distinct_key      | NULL      | NULL    | NULL                      |    1 |                          |
      |    1 | PRIMARY      | e           | eq_ref | PRIMARY           | PRIMARY   | 4       | employees.salaries.emp_no |    1 |                          |
      |    2 | MATERIALIZED | salaries    | range  | PRIMARY,ix_salary | ix_salary | 4       | NULL                      |    1 | Using where; Using index |
      +------+--------------+-------------+--------+-------------------+-----------+---------+---------------------------+------+--------------------------+
      3 rows in set (0.00 sec)
      
      --INSERT
      MariaDB [employees]> explain
          -> insert into employees values (1, '2014-01-01', 'Matt', 'Lee', 'M', '2014-01-02');
      +------+-------------+-----------+------+---------------+------+---------+------+------+-------+
      | id   | select_type | table     | type | possible_keys | key  | key_len | ref  | rows | Extra |
      +------+-------------+-----------+------+---------------+------+---------+------+------+-------+
      |    1 | INSERT      | employees | ALL  | NULL          | NULL | NULL    | NULL | NULL | NULL  |
      +------+-------------+-----------+------+---------------+------+---------+------+------+-------+
      1 row in set (0.00 sec)
      
      MariaDB [employees]> explain
          -> update employees set gender='F' where first_name='Matt';
      +------+-------------+-----------+-------+---------------+--------------+---------+------+------+-------------+
      | id   | select_type | table     | type  | possible_keys | key          | key_len | ref  | rows | Extra       |
      +------+-------------+-----------+-------+---------------+--------------+---------+------+------+-------------+
      |    1 | SIMPLE      | employees | range | ix_firstname  | ix_firstname | 16      | NULL |  233 | Using where |
      +------+-------------+-----------+-------+---------------+--------------+---------+------+------+-------------+
      1 row in set (0.00 sec)
      
    • table 컬럼
      1. 테이블 이름에 별칭이 있는 경우 실행 계획에서 별칭으로 표시
      2. 테이블이 없거나 dual 테이블 사용 시 NULL로 표시
        MariaDB [employees]> explain select now();
        +------+-------------+-------+------+---------------+------+---------+------+------+----------------+
        | id   | select_type | table | type | possible_keys | key  | key_len | ref  | rows | Extra          |
        +------+-------------+-------+------+---------------+------+---------+------+------+----------------+
        |    1 | SIMPLE      | NULL  | NULL | NULL          | NULL | NULL    | NULL | NULL | No tables used |
        +------+-------------+-------+------+---------------+------+---------+------+------+----------------+
        1 row in set (0.00 sec)
        
        MariaDB [employees]> explain select now() from dual;
        +------+-------------+-------+------+---------------+------+---------+------+------+----------------+
        | id   | select_type | table | type | possible_keys | key  | key_len | ref  | rows | Extra          |
        +------+-------------+-------+------+---------------+------+---------+------+------+----------------+
        |    1 | SIMPLE      | NULL  | NULL | NULL          | NULL | NULL    | NULL | NULL | No tables used |
        +------+-------------+-------+------+---------------+------+---------+------+------+----------------+
        1 row in set (0.00 sec)
        
    • type 컬럼: 각 테이블의 레코드를 어떤 방식으로 읽었는지를 나타냄
      system 레코드가 1건만 존재하는 테이블 또는 한 건도 존재하는 않는 테이블을 참조하는 형태의 접근 방법, InnoDB, XtraDB 스토리지 엔진에서는 안나오고 MyISAM, MEMORY 테이블에서만 사용
      const 테이블의 레코드의 건수에 관계없이 쿼리가 프라이머리 키나 유니크 키 컬럼을 이용하는 where 조건절을 가지고 있으며, 반드시 1건을 반환하는 쿼리의 처리 방식
      eq_ref 조인에서 처음 읽은 테이블의 컬럼 값을 그 다음 읽어야 할 테이블의 프라이머리 키나 유니크 키 컬럼의 검색 조건에 사용할 때
      ref 조인의 순서와 인덱스의 종류에 관계없이 동등 조건으로 검색
      fulltext MariaDB의 전문 검색 인덱스를 사용해 레코드를 읽는 접근 방법을 의미
      ref_or_null ref 방식 또는 NULL 비교 접근 방식
      unique_subquery where 조건절에서 사용될 수 있는 IN(sebquery)형태의 쿼리를 위한 접근 방식
      index_subquery IN(subquery)형태의 조건에서 subquery의 반환 값에 중복된 값이 있을 수 있지만 인덱스를 이용해 중복된 값을 제거
      range 인덱스 레인지 스캔 형태의 접근 방법
      index_merge 2개 이상의 인덱스를 이용해 각각의 검색 결과를 만들어낸 후 그 결과를 병합하는 처리 방식
      index 인덱스 풀 스캔
      ALL 테이블 풀 스캔
      
      -- const
      MariaDB [employees]> explain select * from employees where emp_no=10001;
      +------+-------------+-----------+-------+---------------+---------+---------+-------+------+-------+
      | id   | select_type | table     | type  | possible_keys | key     | key_len | ref   | rows | Extra |
      +------+-------------+-----------+-------+---------------+---------+---------+-------+------+-------+
      |    1 | SIMPLE      | employees | const | PRIMARY       | PRIMARY | 4       | const |    1 |       |
      +------+-------------+-----------+-------+---------------+---------+---------+-------+------+-------+
      1 row in set (0.00 sec)
      
      --eq_ref
      MariaDB [employees]> explain
          -> select * from dept_emp de, employees e
          -> where e.emp_no=de.emp_no and de.dept_no='d005';
      +------+-------------+-------+--------+---------------------------+---------+---------+---------------------+--------+-------------+
      | id   | select_type | table | type   | possible_keys             | key     | key_len | ref                 | rows   | Extra       |
      +------+-------------+-------+--------+---------------------------+---------+---------+---------------------+--------+-------------+
      |    1 | SIMPLE      | de    | ref    | PRIMARY,ix_empno_fromdate | PRIMARY | 4       | const               | 165785 | Using where |
      |    1 | SIMPLE      | e     | eq_ref | PRIMARY                   | PRIMARY | 4       | employees.de.emp_no |      1 |             |
      +------+-------------+-------+--------+---------------------------+---------+---------+---------------------+--------+-------------+
      2 rows in set (0.00 sec)
      
      --ref
      MariaDB [employees]> explain
          -> select * from dept_emp where dept_no='d005';
      +------+-------------+----------+------+---------------+---------+---------+-------+--------+-------------+
      | id   | select_type | table    | type | possible_keys | key     | key_len | ref   | rows   | Extra       |
      +------+-------------+----------+------+---------------+---------+---------+-------+--------+-------------+
      |    1 | SIMPLE      | dept_emp | ref  | PRIMARY       | PRIMARY | 4       | const | 165785 | Using where |
      +------+-------------+----------+------+---------------+---------+---------+-------+--------+-------------+
      1 row in set (0.00 sec)
      
      --fulltext
      MariaDB [employees]> explain
          -> select *
          -> from employee_name
          -> where match(first_name, last_name) against ('Facello' in boolean mode);
      +------+-------------+---------------+----------+---------------+---------+---------+------+------+-------------+
      | id   | select_type | table         | type     | possible_keys | key     | key_len | ref  | rows | Extra       |
      +------+-------------+---------------+----------+---------------+---------+---------+------+------+-------------+
      |    1 | SIMPLE      | employee_name | fulltext | fx_name       | fx_name | 0       |      |    1 | Using where |
      +------+-------------+---------------+----------+---------------+---------+---------+------+------+-------------+
      1 row in set (0.00 sec)
      
      --ref_or_null
      MariaDB [employees]> explain
          -> select *
          -> from titles where to_date='1985-03-01' or to_date is null;
      +------+-------------+--------+-------------+---------------+-----------+---------+-------+------+--------------------------+
      | id   | select_type | table  | type        | possible_keys | key       | key_len | ref   | rows | Extra                    |
      +------+-------------+--------+-------------+---------------+-----------+---------+-------+------+--------------------------+
      |    1 | SIMPLE      | titles | ref_or_null | ix_todate     | ix_todate | 4       | const |    2 | Using where; Using index |
      +------+-------------+--------+-------------+---------------+-----------+---------+-------+------+--------------------------+
      1 row in set (0.01 sec)
      
      --range
      MariaDB [employees]> explain
          -> select * from employees where emp_no between 10002 and 10004;
      +------+-------------+-----------+-------+---------------+---------+---------+------+------+-------------+
      | id   | select_type | table     | type  | possible_keys | key     | key_len | ref  | rows | Extra       |
      +------+-------------+-----------+-------+---------------+---------+---------+------+------+-------------+
      |    1 | SIMPLE      | employees | range | PRIMARY       | PRIMARY | 4       | NULL |    3 | Using where |
      +------+-------------+-----------+-------+---------------+---------+---------+------+------+-------------+
      1 row in set (0.00 sec)
      
      --index_merge
      MariaDB [employees]> explain
          -> select *
          -> from employees
          -> where emp_no between 10001 and 11000
          -> or first_name='Smith';
      +------+-------------+-----------+-------------+----------------------+----------------------+---------+------+------+------------------------------------------------+
      | id   | select_type | table     | type        | possible_keys        | key                  | key_len | ref  | rows | Extra                                          |
      +------+-------------+-----------+-------------+----------------------+----------------------+---------+------+------+------------------------------------------------+
      |    1 | SIMPLE      | employees | index_merge | PRIMARY,ix_firstname | PRIMARY,ix_firstname | 4,16    | NULL | 1000 | Using union(PRIMARY,ix_firstname); Using where |
      +------+-------------+-----------+-------------+----------------------+----------------------+---------+------+------+------------------------------------------------+
      1 row in set (0.00 sec)
      
      --index
      MariaDB [employees]> explain
          -> select *
          -> from departments
          -> order by dept_name desc limit 10;
      +------+-------------+-------------+-------+---------------+-------------+---------+------+------+-------------+
      | id   | select_type | table       | type  | possible_keys | key         | key_len | ref  | rows | Extra       |
      +------+-------------+-------------+-------+---------------+-------------+---------+------+------+-------------+
      |    1 | SIMPLE      | departments | index | NULL          | ux_deptname | 42      | NULL |    9 | Using index |
      +------+-------------+-------------+-------+---------------+-------------+---------+------+------+-------------+
      1 row in set (0.00 sec)
      
    • possibel_keys 컬럼
      1. 옵티마이저가 최적의 실행 계획을 만들기 위해 후보로 선정했던 접근 방식에서 사용되는 인덱스 목록
      2. "사용될 법했던 인덱스의 목록"으로 실제 그 인덱스를 사용하지는 않을 수 있음
    • key 컬럼
      1. 최종 선택된 실행 계획에서 사용하는 인덱스를 의미
      2. PRIMARY인 경우에는 프라이머리 키를 사용한다는 의미, 그 의외의 값은 테이블이나 인덱스를 생성할 때 부여했던 고유 이름
    • key_len 컬럼
      1. 쿼리를 처리하기 위해 다중 컬럼으로 구성된 인덱스에서 몇 개의 컬럼까지 사용했는지 표시
      2. 인덱스의 각 레코드에서 몇 바이트까지 사용했는지 알려주는 값
        MariaDB [employees]> explain
            -> select * from dept_emp where dept_no='d005';
        +------+-------------+----------+------+---------------+---------+---------+-------+--------+-------------+
        | id   | select_type | table    | type | possible_keys | key     | key_len | ref   | rows   | Extra       |
        +------+-------------+----------+------+---------------+---------+---------+-------+--------+-------------+
        |    1 | SIMPLE      | dept_emp | ref  | PRIMARY       | PRIMARY | 4       | const | 165785 | Using where |
        +------+-------------+----------+------+---------------+---------+---------+-------+--------+-------------+
        1 row in set (0.00 sec)
        
        MariaDB [employees]> explain
            -> select * from dept_emp where dept_no='d005' and emp_no=10001;
        +------+-------------+----------+-------+---------------------------+---------+---------+-------------+------+-------+
        | id   | select_type | table    | type  | possible_keys             | key     | key_len | ref         | rows | Extra |
        +------+-------------+----------+-------+---------------------------+---------+---------+-------------+------+-------+
        |    1 | SIMPLE      | dept_emp | const | PRIMARY,ix_empno_fromdate | PRIMARY | 8       | const,const |    1 |       |
        +------+-------------+----------+-------+---------------------------+---------+---------+-------------+------+-------+
        1 row in set (0.00 sec)
        
        MariaDB [employees]> explain
            -> select * from titles where to_date <= '1985-10-10';
        +------+-------------+--------+-------+---------------+-----------+---------+------+------+--------------------------+
        | id   | select_type | table  | type  | possible_keys | key       | key_len | ref  | rows | Extra                    |
        +------+-------------+--------+-------+---------------+-----------+---------+------+------+--------------------------+
        |    1 | SIMPLE      | titles | range | ix_todate     | ix_todate | 4       | NULL |   51 | Using where; Using index |
        +------+-------------+--------+-------+---------------+-----------+---------+------+------+--------------------------+
        1 row in set (0.00 sec)
        -- to_date is nullable: date 3byte + null 1byte
        
    • ref 컬럼
      1. 참조 조건(equal 비교 조건)으로 어떤 값이 제공됐는지 표시
      2. 상수 값을 지정했다면 const로 표시, 다른 테이블의 컬럼이면 그 테이블 명과 컬럼 명이 표시
        MariaDB [employees]> explain
            -> select * from employees e, dept_emp de
            -> where e.emp_no=de.emp_no;
        +------+-------------+-------+--------+-------------------+---------+---------+---------------------+--------+-------+
        | id   | select_type | table | type   | possible_keys     | key     | key_len | ref                 | rows   | Extra |
        +------+-------------+-------+--------+-------------------+---------+---------+---------------------+--------+-------+
        |    1 | SIMPLE      | de    | ALL    | ix_empno_fromdate | NULL    | NULL    | NULL                | 331570 |       |
        |    1 | SIMPLE      | e     | eq_ref | PRIMARY           | PRIMARY | 4       | employees.de.emp_no |      1 |       |
        +------+-------------+-------+--------+-------------------+---------+---------+---------------------+--------+-------+
        2 rows in set (0.00 sec)
        
        MariaDB [employees]> explain
            -> select * from employees e, dept_emp de
            -> where e.emp_no=(de.emp_no-1);
        +------+-------------+-------+--------+---------------+---------+---------+------+--------+-------------+
        | id   | select_type | table | type   | possible_keys | key     | key_len | ref  | rows   | Extra       |
        +------+-------------+-------+--------+---------------+---------+---------+------+--------+-------------+
        |    1 | SIMPLE      | de    | ALL    | NULL          | NULL    | NULL    | NULL | 331570 |             |
        |    1 | SIMPLE      | e     | eq_ref | PRIMARY       | PRIMARY | 4       | func |      1 | Using where |
        +------+-------------+-------+--------+---------------+---------+---------+------+--------+-------------+
        2 rows in set (0.00 sec)
        
    • rows 컬럼: 실행 계획의 효율성 판단을 위해 예측했던 레코드 건수를 표시
    • extra 컬럼
      constrow not found 쿼리의 실행계획에서 const 접근 방식으로 테이블을 읽었지만 실제로 해당 테이블에 레코드가 1건도 존재하지 않는 경우
      Distinct 중복 제거 표시
      Full scan on NUll key col1 IN (select col2 from ...) 쿼리에서 col1이 값이 NULL이면 풀 테이블 스캔을 사용할 것을 표시
      Impossible HAVING 쿼리에 사용된 having절의 조건을 만족하는 레코드가 없을 때 표시, 쿼리가 제대로 작성되지 못한 경우가 대부분으로 쿼리를 다시 점검
      Impossible WHERE where 조건이 항상 false가 될 수밖에 없는 경우
      Impossible WHERE noticed after reading const tables 실행 계획을 만드는 과정에서 쿼리의 일부분을 실행해 본 후 where 조건이 false인 경우
      No matching min/max row min(), max()와 같은 집합 함수가 있는 쿼리의 조건절에 일치하는 레코드가 한 건도 없을 때 표시
      No matching row in const table 조인에 사용된 테이블에서 const방식으로 접근할 때 일치하는 레코드가 없는 것을 표시
      No tables used from절이 없는 쿼리 문장이나 "from dual"을 표시
      Not exists outer조인을 이용해 안티-조인을 수행하는 쿼리 표시
      Range checked for each record(index map: N) 조인 조건이 모두 변수인 경우 매 레코드마다 인덱스 레인지 스캔을 표시
      
      --Distinct
      MariaDB [employees]> explain
          -> select distinct d.dept_no
          -> from departments d, dept_emp de where de.dept_no=d.dept_no;
      +------+-------------+-------+-------+---------------+---------+---------+---------------------+-------+------------------------------+
      | id   | select_type | table | type  | possible_keys | key     | key_len | ref                 | rows  | Extra                        |
      +------+-------------+-------+-------+---------------+---------+---------+---------------------+-------+------------------------------+
      |    1 | SIMPLE      | d     | index | PRIMARY       | PRIMARY | 4       | NULL                |     9 | Using index; Using temporary |
      |    1 | SIMPLE      | de    | ref   | PRIMARY       | PRIMARY | 4       | employees.d.dept_no | 20723 | Using index; Distinct        |
      +------+-------------+-------+-------+---------------+---------+---------+---------------------+-------+------------------------------+
      2 rows in set (0.00 sec)
      
      --Full scan on NULL key
      MariaDB [employees]> explain
          -> select d.dept_no, null in (select id.dept_name from departments id)
          -> from departments d;
      +------+-------------+-------+----------------+---------------+-------------+---------+-------+------+-------------------------------------------------+
      | id   | select_type | table | type           | possible_keys | key         | key_len | ref   | rows | Extra                                           |
      +------+-------------+-------+----------------+---------------+-------------+---------+-------+------+-------------------------------------------------+
      |    1 | PRIMARY     | d     | index          | NULL          | PRIMARY     | 4       | NULL  |    9 | Using index                                     |
      |    2 | SUBQUERY    | id    | index_subquery | ux_deptname   | ux_deptname | 42      | const |    1 | Using index; Using where; Full scan on NULL key |
      +------+-------------+-------+----------------+---------------+-------------+---------+-------+------+-------------------------------------------------+
      2 rows in set (0.00 sec)
      
      --Impossible HAVING
      MariaDB [employees]> explain
          -> select e.emp_no, count(*) as cnt
          -> from employees e
          -> where e.emp_no=10001
          -> group by e.emp_no
          -> having e.emp_no is null;
      +------+-------------+-------+------+---------------+------+---------+------+------+-------------------+
      | id   | select_type | table | type | possible_keys | key  | key_len | ref  | rows | Extra             |
      +------+-------------+-------+------+---------------+------+---------+------+------+-------------------+
      |    1 | SIMPLE      | NULL  | NULL | NULL          | NULL | NULL    | NULL | NULL | Impossible HAVING |
      +------+-------------+-------+------+---------------+------+---------+------+------+-------------------+
      1 row in set (0.00 sec)
      
      --Impossible WHERE
      MariaDB [employees]> explain
          -> select * from employees where emp_no is null;
      +------+-------------+-------+------+---------------+------+---------+------+------+------------------+
      | id   | select_type | table | type | possible_keys | key  | key_len | ref  | rows | Extra            |
      +------+-------------+-------+------+---------------+------+---------+------+------+------------------+
      |    1 | SIMPLE      | NULL  | NULL | NULL          | NULL | NULL    | NULL | NULL | Impossible WHERE |
      +------+-------------+-------+------+---------------+------+---------+------+------+------------------+
      1 row in set (0.00 sec)
      
      --Impossible WHERE noticed after reading const tables
      MariaDB [employees]> explain
          -> select * from employees where emp_no=0;
      +------+-------------+-------+------+---------------+------+---------+------+------+-----------------------------------------------------+
      | id   | select_type | table | type | possible_keys | key  | key_len | ref  | rows | Extra                                               |
      +------+-------------+-------+------+---------------+------+---------+------+------+-----------------------------------------------------+
      |    1 | SIMPLE      | NULL  | NULL | NULL          | NULL | NULL    | NULL | NULL | Impossible WHERE noticed after reading const tables |
      +------+-------------+-------+------+---------------+------+---------+------+------+-----------------------------------------------------+
      1 row in set (0.00 sec)
      
      --No matching min/max row
      MariaDB [employees]> explain
          -> select min(dept_no), max(dept_no)
          -> from dept_emp where dept_no='';
      +------+-------------+-------+------+---------------+------+---------+------+------+-------------------------+
      | id   | select_type | table | type | possible_keys | key  | key_len | ref  | rows | Extra                   |
      +------+-------------+-------+------+---------------+------+---------+------+------+-------------------------+
      |    1 | SIMPLE      | NULL  | NULL | NULL          | NULL | NULL    | NULL | NULL | No matching min/max row |
      +------+-------------+-------+------+---------------+------+---------+------+------+-------------------------+
      1 row in set (0.00 sec)
      
      --No tables used
      MariaDB [employees]> explain select now();
      +------+-------------+-------+------+---------------+------+---------+------+------+----------------+
      | id   | select_type | table | type | possible_keys | key  | key_len | ref  | rows | Extra          |
      +------+-------------+-------+------+---------------+------+---------+------+------+----------------+
      |    1 | SIMPLE      | NULL  | NULL | NULL          | NULL | NULL    | NULL | NULL | No tables used |
      +------+-------------+-------+------+---------------+------+---------+------+------+----------------+
      1 row in set (0.00 sec)
      
      MariaDB [employees]> explain select now() from dual;
      +------+-------------+-------+------+---------------+------+---------+------+------+----------------+
      | id   | select_type | table | type | possible_keys | key  | key_len | ref  | rows | Extra          |
      +------+-------------+-------+------+---------------+------+---------+------+------+----------------+
      |    1 | SIMPLE      | NULL  | NULL | NULL          | NULL | NULL    | NULL | NULL | No tables used |
      +------+-------------+-------+------+---------------+------+---------+------+------+----------------+
      1 row in set (0.00 sec)
      
      --Not exists
      MariaDB [employees]> explain
          -> select *
          -> from dept_emp de
          -> left join departments d on de.dept_no=d.dept_no
          -> where d.dept_no is null;
      +------+-------------+-------+--------+---------------+---------+---------+----------------------+--------+-------------------------+
      | id   | select_type | table | type   | possible_keys | key     | key_len | ref                  | rows   | Extra                   |
      +------+-------------+-------+--------+---------------+---------+---------+----------------------+--------+-------------------------+
      |    1 | SIMPLE      | de    | ALL    | NULL          | NULL    | NULL    | NULL                 | 331570 |                         |
      |    1 | SIMPLE      | d     | eq_ref | PRIMARY       | PRIMARY | 4       | employees.de.dept_no |      1 | Using where; Not exists |
      +------+-------------+-------+--------+---------------+---------+---------+----------------------+--------+-------------------------+
      2 rows in set (0.00 sec)
      
      --Range checked for each record
      MariaDB [employees]> explain select * from employees e1, employees e2 where e2.emp_no >= e1.emp_no;
      +------+-------------+-------+------+---------------+------+---------+------+--------+------------------------------------------------+
      | id   | select_type | table | type | possible_keys | key  | key_len | ref  | rows   | Extra                                          |
      +------+-------------+-------+------+---------------+------+---------+------+--------+------------------------------------------------+
      |    1 | SIMPLE      | e1    | ALL  | PRIMARY       | NULL | NULL    | NULL | 299335 |                                                |
      |    1 | SIMPLE      | e2    | ALL  | PRIMARY       | NULL | NULL    | NULL | 299335 | Range checked for each record (index map: 0x1) |
      +------+-------------+-------+------+---------------+------+---------+------+--------+------------------------------------------------+
      2 rows in set (0.00 sec)
      

문서정보

Enter labels to add to this page:
Please wait 
Looking for a label? Just start typing.