EXPLAIN 명령을 실행하면 표 형태로 된 1줄 이상의 결과가 표시된다.SELECT 쿼리별로 부여되는 식별자 값이다.
SELECT 쿼리를 가지는 경우 최소 2개의 id 값이 표시될 것이다.테이블을 조인하면 조인되는 테이블 개수만큼 실행 계획 레코드가 출력되지만 같은 id 값이 부여된다.
EXPLAIN
SELECT e.emp_no, e.first_name, s.from_Date, s.salary
FROM employees e, salaryies s
WHERE e.emp_no=s.emp_no LIMIT 10;
| id | select_type | table | key | ref | rows | Extra |
|---|---|---|---|---|---|---|
| 1 | SIMPLE | e | ix_firstname | NULL | 3000252 | Using index |
| 1 | SIMPLE | s | PRRIMARY | employees.e.emp_no | 10 | NULL |
SELECT 쿼리가 어떤 타입 쿼리인지 표시되는 칼럼이다.UNION이나 서브 쿼리를 사용하지 않는 단순 SELECT 쿼리
SELECT 쿼리가 SIMPLE로 표시된다.UNION이나 서브 쿼리를 가지는 SELECT 쿼리에서 가장 바깥쪽(Outer)에 있는 단위 쿼리EXPLAIN SELECT * 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 | key | ref | rows | Extra |
|---|---|---|---|---|---|---|---|
| 1 | PRIMARY | ALL | NULL | NULL | 30 | NULL | |
| 2 | DERIVED | e1 | index | ix_hiredate | NULL | 30252 | Using index |
| 3 | UNION | e2 | index | ix_hiredate | NULL | 30252 | Using index |
| 4 | UNION | e3 | index | ix_hiredate | NULL | 30252 | Using index |
UNION ALL로 결합해 임시 테이블을 만들어 사용하고 있다.UNION이나 UNION ALL로 결합된 쿼리가 외부 쿼리에 의해 영향을 받을 때 표시된다.EXPLAIN SELECT * FROM employees e1 WHERE e1.emp_no
IN (
SELECT e2.emp_no FROM employees e2.first_name='Matt'
UNION
SELECT e3.emp_no FROM employees e3 WHERE e3.last_name='Matt'
);
employees 테이블을 먼저 읽은 다음 서브 쿼리를 실행하기 때문에 employees 테이블 칼럼 값이 서브 쿼리에 영향을 준다.| id | select_type | table | type | key | ref | rows | Extra |
|---|---|---|---|---|---|---|---|
| 1 | PRIMARY | e1 | ALL | NULL | NULL | 30252 | Using where |
| 2 | DEPENDENT SUBQUERY | e2 | eq_ref | PRIMARY | func | 1 | Using where |
| 3 | DEPENDENT UNION | e3 | eq_ref | PRIMARY | func | 1 | Using where |
| NULL | UNION RESULT | <union2,3> | ALL | NULL | NULL | NULL | Using temporary |
UNION 쿼리의 WHERE 조건에 e2.emp_no=e1.emp_no와 e3.emp_no=e1.emp_no 조건이 자동으로 추가된다.UNION 결과를 담아두는 테이블이다. (임시 테이블)
UNION ALL을 사용하는 경우엔 임시 테이블을 사용하지 않도록 기능이 개선되었다.UNION, UNION DISTINCT의 경우 여전히 임시 테이블에 결과를 버퍼링한다.<union1,2>처럼 표시되는데 이는 id 1과 2를 결합했다는 것을 의미한다.FROM 절 이외에 사용되는 서브 쿼리는 select_type에 SUBQUERY가 표시된다.
FROM 절에 사용된 서브 쿼리는 DERIVED로 표시된다.EXPLAIN SELECT e.first_name, (
SELECT COUNT(*)
FROM dept_emp de, dept_manager dm
WHERE dm.dept_no=de.dept_no
) AS cnt
FROM employees e WHERE e.emp_no=10001;
| id | select_type | table | type | key | rows | Extra |
|---|---|---|---|---|---|---|
| 1 | PRIMARY | e | const | PRIMARY | 1 | NULL |
| 2 | SUBQUERY | dm | index | PRIMARY | 24 | Using index |
| 2 | SUBQUERY | de | ref | PRIMARY | 41392 | Using index |
SELECT되는 칼럼에 사용된 서브 쿼리WHERE 절에 사용된 일반적인 서브 쿼리FROM 절에 사용된 서브 쿼리를 MySQL에서는 파생 테이블이라고 하며 일반적인 RDBMS에선 Inline View 또는 Sub Select라고 부른다.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';
SELECT 쿼리의 칼럼에 의존하기에 DEPENDENT 키워드가 붙는다.
e.emp_no가 내부 쿼리 WHERE 절에 쓰이고 있다.SELECT 쿼리의 실행 결과로 메모리나 디스크에 임시 테이블을 생성하는 것을 의미한다.
FROM 절의 서브 쿼리는 항상 파생 테이블을 만들었지만 5.6 버전부턴 옵티마이저 옵션에 따라 외부 쿼리와 통합하는 최적화가 수행되기도 한다.FROM 절의 서브 쿼리를 최적화하여 조인으로 재작성해주지만 옵티마이저의 한계가 있으므로 직접 최적화된 쿼리 작성을 권장한다.FROM 절 서브 쿼리에서도 외부 쿼리 칼럼을 참조할 수 있게 되었다.
LATERAL 키워드가 없으면 오류가 발생한다.EXPLAIN SELECT *
FROM employees e
LEFT JOIN LATERAL
(SELECT * FROM salaries s
WHERE s.emp_no=e.emp_no
ORDER BY s.from_date DESC LIMIT 2) AS s2
ON s2.emp_no=e.emp_no;
| id | select_type | table | type | key | Extra |
|---|---|---|---|---|---|
| 1 | PRIMARY | e | ALL | NULL | Rematerialize ( |
| 1 | PRIMARY | ref | NULL | ||
| 2 | DEPENDENT DERIVED | s | ref | PRIMARY | Using filesort |
FROM 절이나 IN(subquery) 형태의 쿼리에 사용된 서브 쿼리 최적화를 위해 사용된다.EXPLAIN SELECT * FROM employees e
WHERE e.emp_no IN
(SELECT emp_no FROM salaries
WHERE salary BETWEEN 100 AND 1000);
employees 테이블을 읽어 레코드마다 서브 쿼리가 실행되는 것이 아닌, 서브 쿼리 내용을 임시 테이블로 구체화한 후 임시 테이블과 employees 테이블을 조인하는 형태로 최적화한다.