Real MariaDB (2017년)
실행 계획 분석 Part 1 0 0 50,100

by 구루비스터디 MariaDB 실행계획 MariaDB 옵티마이저 MariaDB 히스토그램 [2019.08.11]


4.3 실행 계획 분석


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)


  • 레코드는 쿼리 문장에서 사용된 테이블의 개수만큼 출력(임시테이블 포함)
  • 실행 순서는 위에서 아래로 순서대로 표시(union이나 상관 서브 쿼리와 같은 경우 순서대로 표시되지 않을 수 있음)
  • 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 컬럼

SIMPLEunion이나 서브 쿼리를 사용하지 않는 단순한 select 쿼리, 실행계획에서 SIMPLE은 하나만 존재하며 일반적으로 제일 바깥 select쿼리가 SIMPLE로 표시
PRIMARYunion이나 서브 쿼리를 가지는 select 쿼리의 실행 계획에서 가장 바깥쪽(outer)에 있는 단위 쿼리, 실행계획에서 하나만 존재하며 일반적으로 제일 바깥 select쿼리가 PRIMARY로 표시
UNIONunion으로 결합하는 단위 select쿼리 가운데 첫 번째를 제외한 두 번째 이후 단위 select 쿼리
DEPENDENT UNIONunion이나 union all로 결합된 단위 쿼리가 외부의 의해 영향을 받는 쿼리
UNION RESULTunion 결과 테이블을 의미, id 값이 부여되지 않음
SUBQUERYfrom절 이외에서 사용되는 서브 쿼리만을 의미
DEPENDENT SUBQUERY서브 쿼리가 바깥쪽(outer) select 쿼리에서 정의된 컬럼을 사용하는 경우
DERIVED단위 select쿼리의 실행 결과를 메모리나 디스크에 임시 테이블을 생성하는 것을 의미, 서브 쿼리가 from절에 사용된 경우
UNCACHEABLE SUBQUERY서브 쿼리 결과를 내부적인 캐시 공간에 저장되지 못하는 경우
1. 사용자 변수가 서브 쿼리에 사용된 경우
2. not-deterministic 속성의 스토어드 루틴이 서브 쿼리 내에 사용된 경우
3. UUID()나 RAND()와 같이 결과값이 호출될 때마다 달라지는 함수가 서브 쿼리에 사용된 경우
UNCACHEABLE UNIONunion 쿼리 결과가 내부적인 캐시 공간에 저장되지 못하는 경우
MATERIALIZED서브 쿼리의 내용을 임시 테이블로 구체화(materialization)하는 경우
INSERTinsert문의 실행계획



--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 컬럼

  • 테이블 이름에 별칭이 있는 경우 실행 계획에서 별칭으로 표시
  • 테이블이 없거나 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조인의 순서와 인덱스의 종류에 관계없이 동등 조건으로 검색
fulltextMariaDB의 전문 검색 인덱스를 사용해 레코드를 읽는 접근 방법을 의미
ref_or_nullref 방식 또는 NULL 비교 접근 방식
unique_subquerywhere 조건절에서 사용될 수 있는 IN(sebquery)형태의 쿼리를 위한 접근 방식
index_subqueryIN(subquery)형태의 조건에서 subquery의 반환 값에 중복된 값이 있을 수 있지만 인덱스를 이용해 중복된 값을 제거
range인덱스 레인지 스캔 형태의 접근 방법
index_merge2개 이상의 인덱스를 이용해 각각의 검색 결과를 만들어낸 후 그 결과를 병합하는 처리 방식
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 컬럼

  • 옵티마이저가 최적의 실행 계획을 만들기 위해 후보로 선정했던 접근 방식에서 사용되는 인덱스 목록
  • "사용될 법했던 인덱스의 목록"으로 실제 그 인덱스를 사용하지는 않을 수 있음


key 컬럼

  • 최종 선택된 실행 계획에서 사용하는 인덱스를 의미
  • PRIMARY인 경우에는 프라이머리 키를 사용한다는 의미, 그 의외의 값은 테이블이나 인덱스를 생성할 때 부여했던 고유 이름


key_len 컬럼

  • 쿼리를 처리하기 위해 다중 컬럼으로 구성된 인덱스에서 몇 개의 컬럼까지 사용했는지 표시
  • 인덱스의 각 레코드에서 몇 바이트까지 사용했는지 알려주는 값

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 컬럼

  • 참조 조건(equal 비교 조건)으로 어떤 값이 제공됐는지 표시
  • 상수 값을 지정했다면 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 keycol1 IN (select col2 from ...) 쿼리에서 col1이 값이 NULL이면 풀 테이블 스캔을 사용할 것을 표시
Impossible HAVING쿼리에 사용된 having절의 조건을 만족하는 레코드가 없을 때 표시, 쿼리가 제대로 작성되지 못한 경우가 대부분으로 쿼리를 다시 점검
Impossible WHEREwhere 조건이 항상 false가 될 수밖에 없는 경우
Impossible WHERE noticed after reading const tables실행 계획을 만드는 과정에서 쿼리의 일부분을 실행해 본 후 where 조건이 false인 경우
No matching min/max rowmin(), max()와 같은 집합 함수가 있는 쿼리의 조건절에 일치하는 레코드가 한 건도 없을 때 표시
No matching row in const table조인에 사용된 테이블에서 const방식으로 접근할 때 일치하는 레코드가 없는 것을 표시
No tables usedfrom절이 없는 쿼리 문장이나 "from dual"을 표시
Not existsouter조인을 이용해 안티-조인을 수행하는 쿼리 표시
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)

"구루비 데이터베이스 스터디모임" 에서 2017년에 "Real MariaDB" 도서를 스터디하면서 정리한 내용 입니다.

- 강좌 URL : http://www.gurubee.net/lecture/4187

- 구루비 강좌는 개인의 학습용으로만 사용 할 수 있으며, 다른 웹 페이지에 게재할 경우에는 출처를 꼭 밝혀 주시면 고맙겠습니다.~^^

- 구루비 강좌는 서비스 제공을 위한 목적이나, 학원 홍보, 수익을 얻기 위한 용도로 사용 할 수 없습니다.

댓글등록
SQL문을 포맷에 맞게(깔끔하게) 등록하려면 code() 버튼을 클릭하여 작성 하시면 됩니다.
로그인 사용자만 댓글을 작성 할 수 있습니다. 로그인, 회원가입