4.3.10.15 Unique row not found


create table tb_test1 (a int, primary key(a));
create table tb_test2 (a int, primary key(a));

insert into tb_test1 values(1),(2);
insert into tb_test2 values(1);

EXPLAIN
SELECT t1.a
FROM   tb_test1 t1 left join tb_test2 t2
ON     t1.a=t2.a
WHERE  t1.a=2;

+------+-------------+-------+-------+---------------+---------+---------+-------+------+-------------+
| id   | select_type | table | type  | possible_keys | key     | key_len | ref   | rows | Extra       |
+------+-------------+-------+-------+---------------+---------+---------+-------+------+-------------+
|    1 | SIMPLE      | t1    | const | PRIMARY       | PRIMARY | 4       | const |    1 | Using index |
+------+-------------+-------+-------+---------------+---------+---------+-------+------+-------------+


4.3.10.16 Unique row not found


EXPLAIN
SELECT * FROM employees ORDER BY last_name DESC;

+------+-------------+-----------+------+---------------+------+---------+------+--------+----------------+
| id   | select_type | table     | type | possible_keys | key  | key_len | ref  | rows   | Extra          |
+------+-------------+-----------+------+---------------+------+---------+------+--------+----------------+
|    1 | SIMPLE      | employees | ALL  | NULL          | NULL | NULL    | NULL | 299202 | Using filesort |
+------+-------------+-----------+------+---------------+------+---------+------+--------+----------------+
1 row in set (0.00 sec)


4.3.10.17 Using index


EXPLAIN
SELECT first_name, birth_date
FROM   employees 
WHERE  first_name between 'Babette' AND 'Gad';

+------+-------------+-----------+------+---------------+------+---------+------+--------+-------------+
| id   | select_type | table     | type | possible_keys | key  | key_len | ref  | rows   | Extra       |
+------+-------------+-----------+------+---------------+------+---------+------+--------+-------------+
|    1 | SIMPLE      | employees | ALL  | NULL          | NULL | NULL    | NULL | 299202 | Using where |
+------+-------------+-----------+------+---------------+------+---------+------+--------+-------------+
1 row in set (0.00 sec)


EXPLAIN
SELECT first_name
FROM   employees 
WHERE  first_name between 'Babette' AND 'Gad';

+------+-------------+-----------+------+---------------+------+---------+------+--------+-------------+
| id   | select_type | table     | type | possible_keys | key  | key_len | ref  | rows   | Extra       |
+------+-------------+-----------+------+---------------+------+---------+------+--------+-------------+
|    1 | SIMPLE      | employees | ALL  | NULL          | NULL | NULL    | NULL | 299202 | Using where |
+------+-------------+-----------+------+---------------+------+---------+------+--------+-------------+
1 row in set (0.00 sec)


4.3.10.18 Using index for group-by


EXPLAIN
SELECT first_name, count(*) as counter
FROM   employees 
GROUP BY first_name;

+------+-------------+-----------+------+---------------+------+---------+------+--------+---------------------------------+
| id   | select_type | table     | type | possible_keys | key  | key_len | ref  | rows   | Extra                           |
+------+-------------+-----------+------+---------------+------+---------+------+--------+---------------------------------+
|    1 | SIMPLE      | employees | ALL  | NULL          | NULL | NULL    | NULL | 299202 | Using temporary; Using filesort |
+------+-------------+-----------+------+---------------+------+---------+------+--------+---------------------------------+
1 row in set (0.00 sec)


EXPLAIN
SELECT emp_no, MIN(from_date) , MAX(from_date)
FROM   salaries
GROUP BY emp_no;

+------+-------------+----------+-------+---------------+---------+---------+------+---------+-------------+
| id   | select_type | table    | type  | possible_keys | key     | key_len | ref  | rows    | Extra       |
+------+-------------+----------+-------+---------------+---------+---------+------+---------+-------------+
|    1 | SIMPLE      | salaries | index | NULL          | PRIMARY | 7       | NULL | 2838426 | Using index |
+------+-------------+----------+-------+---------------+---------+---------+------+---------+-------------+
1 row in set (0.06 sec)

EXPLAIN
SELECT first_name
FROM   employees 
WHERE  birth_date > '1994-01-01'
GROUP BY first_name;

+------+-------------+-----------+------+---------------+------+---------+------+--------+----------------------------------------------+
| id   | select_type | table     | type | possible_keys | key  | key_len | ref  | rows   | Extra                                        |
+------+-------------+-----------+------+---------------+------+---------+------+--------+----------------------------------------------+
|    1 | SIMPLE      | employees | ALL  | NULL          | NULL | NULL    | NULL | 299202 | Using where; Using temporary; Using filesort |
+------+-------------+-----------+------+---------------+------+---------+------+--------+----------------------------------------------+
1 row in set (0.00 sec)

EXPLAIN
SELECT emp_no
FROM   salaries
WHERE  emp_no BETWEEN 10001 AND 200000
GROUP BY emp_no;

+------+-------------+----------+-------+---------------+---------+---------+------+---------+--------------------------+
| id   | select_type | table    | type  | possible_keys | key     | key_len | ref  | rows    | Extra                    |
+------+-------------+----------+-------+---------------+---------+---------+------+---------+--------------------------+
|    1 | SIMPLE      | salaries | range | PRIMARY       | PRIMARY | 4       | NULL | 1419213 | Using where; Using index |
+------+-------------+----------+-------+---------------+---------+---------+------+---------+--------------------------+
1 row in set (0.05 sec)


4.3.10.19 Using join buffer(Bloack Nested Loop), Using join buffer(Batched Key Access)


EXPLAIN
SELECT *
FROM   dept_emp b, employees a
WHERE  b.from_date > '2005-01-01' AND a.emp_no <10904;

+------+-------------+-------+-------+---------------+---------+---------+------+--------+-------------------------------------------------+
| id   | select_type | table | type  | possible_keys | key     | key_len | ref  | rows   | Extra                                           |
+------+-------------+-------+-------+---------------+---------+---------+------+--------+-------------------------------------------------+
|    1 | SIMPLE      | a     | range | PRIMARY       | PRIMARY | 4       | NULL |    902 | Using where                                     |
|    1 | SIMPLE      | b     | ALL   | NULL          | NULL    | NULL    | NULL | 331570 | Using where; Using join buffer (flat, BNL join) |
+------+-------------+-------+-------+---------------+---------+---------+------+--------+-------------------------------------------------+
2 rows in set (0.00 sec)


4.3.10.21 Using tempoary


EXPLAIN
SELECT *
FROM   employees
GROUP BY gender
ORDER BY MIN(emp_no);

+------+-------------+-----------+------+---------------+------+---------+------+--------+---------------------------------+
| id   | select_type | table     | type | possible_keys | key  | key_len | ref  | rows   | Extra                           |
+------+-------------+-----------+------+---------------+------+---------+------+--------+---------------------------------+
|    1 | SIMPLE      | employees | ALL  | NULL          | NULL | NULL    | NULL | 299202 | Using temporary; Using filesort |
+------+-------------+-----------+------+---------------+------+---------+------+--------+---------------------------------+
1 row in set (0.00 sec)


4.3.10.22 Using where


EXPLAIN
SELECT *
FROM   employees
WHERE  emp_no BETWEEN 10001 AND 10100 AND gender ='F';

+------+-------------+-----------+-------+---------------+---------+---------+------+------+-------------+
| id   | select_type | table     | type  | possible_keys | key     | key_len | ref  | rows | Extra       |
+------+-------------+-----------+-------+---------------+---------+---------+------+------+-------------+
|    1 | SIMPLE      | employees | range | PRIMARY       | PRIMARY | 4       | NULL |  100 | Using where |
+------+-------------+-----------+-------+---------------+---------+---------+------+------+-------------+
1 row in set (0.01 sec)


4.3.10.24 Deleting all rows


CREATE TABLE tab_delete (fd INT PRIMARY KEY) ENGINE=InnoDB;
INSERT INTO  tab_delete VALUES(1),(2),(3);

EXPLAIN
DELETE FROM tab_delete;

+------+-------------+-------+------+---------------+------+---------+------+------+-------------------+
| id   | select_type | table | type | possible_keys | key  | key_len | ref  | rows | Extra             |
+------+-------------+-------+------+---------------+------+---------+------+------+-------------------+
|    1 | SIMPLE      | NULL  | NULL | NULL          | NULL | NULL    | NULL |    3 | Deleting all rows |
+------+-------------+-------+------+---------------+------+---------+------+------+-------------------+
1 row in set (0.07 sec)

EXPLAIN
DELETE FROM tab_delete WHERE fd=1; 

+------+-------------+------------+-------+---------------+---------+---------+------+------+-------------+
| id   | select_type | table      | type  | possible_keys | key     | key_len | ref  | rows | Extra       |
+------+-------------+------------+-------+---------------+---------+---------+------+------+-------------+
|    1 | SIMPLE      | tab_delete | range | PRIMARY       | PRIMARY | 4       | NULL |    1 | Using where |
+------+-------------+------------+-------+---------------+---------+---------+------+------+-------------+
1 row in set (0.00 sec)


4.3.10.25 FirstMatch(tbl_name)


EXPLAIN
SELECT *
FROM   departments d
WHERE  d.dept_no IN (SELECT de.dept_no FROM dept_emp de);

+------+-------------+-------+-------+---------------+-----------+---------+---------------------+------+----------------------------+
| id   | select_type | table | type  | possible_keys | key       | key_len | ref                 | rows | Extra                      |
+------+-------------+-------+-------+---------------+-----------+---------+---------------------+------+----------------------------+
|    1 | PRIMARY     | d     | index | PRIMARY       | dept_name | 42      | NULL                |    9 | Using index                |
|    1 | PRIMARY     | de    | ref   | dept_no       | dept_no   | 4       | employees.d.dept_no |    1 | Using index; FirstMatch(d) |
+------+-------------+-------+-------+---------------+-----------+---------+---------------------+------+----------------------------+
2 rows in set (0.00 sec)


4.3.10.26 LooseScan(m..n)


SET optimizer_switch=DEFAULT;
SET optimizer_switch='firstmatch=off';
SET optimizer_switch='materialization=off';

EXPLAIN
SELECT *
FROM   departments
WHERE  dept_no IN (SELECT dept_no FROM dept_emp);

+------+-------------+-------------+-------+---------------+-----------+---------+-------------------------------+------+---------------------------------------------+
| id   | select_type | table       | type  | possible_keys | key       | key_len | ref                           | rows | Extra                                       |
+------+-------------+-------------+-------+---------------+-----------+---------+-------------------------------+------+---------------------------------------------+
|    1 | PRIMARY     | departments | index | PRIMARY       | dept_name | 42      | NULL                          |    9 | Using index                                 |
|    1 | PRIMARY     | dept_emp    | ref   | dept_no       | dept_no   | 4       | employees.departments.dept_no |    1 | Using index; Start temporary; End temporary |
+------+-------------+-------------+-------+---------------+-----------+---------+-------------------------------+------+---------------------------------------------+
2 rows in set (0.00 sec)


4.3.10.29 Start tempoary, End tempoary


EXPLAIN
SELECT *
FROM   employees d
WHERE  d.emp_no IN (SELECT de.dept_no FROM dept_emp de WHERE dept_no in ('d001','d003'));

+------+-------------+-------+--------+---------------+---------+---------+----------------------+-------+-------------------------------------------+
| id   | select_type | table | type   | possible_keys | key     | key_len | ref                  | rows  | Extra                                     |
+------+-------------+-------+--------+---------------+---------+---------+----------------------+-------+-------------------------------------------+
|    1 | PRIMARY     | de    | range  | dept_no       | dept_no | 4       | NULL                 | 75424 | Using where; Using index; Start temporary |
|    1 | PRIMARY     | d     | eq_ref | PRIMARY       | PRIMARY | 4       | employees.de.dept_no |     1 | Using where; End temporary                |
+------+-------------+-------+--------+---------------+---------+---------+----------------------+-------+-------------------------------------------+
2 rows in set (0.06 sec)


4.3.10.30 Using index condition


EXPLAIN
SELECT *
FROM   employees
WHERE  first_name LIKE 'Lee%' AND first_name LIKE '%matt';

+------+-------------+-----------+------+---------------+------+---------+------+--------+-------------+
| id   | select_type | table     | type | possible_keys | key  | key_len | ref  | rows   | Extra       |
+------+-------------+-----------+------+---------------+------+---------+------+--------+-------------+
|    1 | SIMPLE      | employees | ALL  | NULL          | NULL | NULL    | NULL | 299202 | Using where |
+------+-------------+-----------+------+---------------+------+---------+------+--------+-------------+
1 row in set (0.00 sec)


4.3.10.31 Rowid-ordered scan, Key-ordered scan


EXPLAIN
SELECT *
FROM   employees
WHERE  first_name >='A' AND first_name <'B';

+------+-------------+-----------+------+---------------+------+---------+------+--------+-------------+
| id   | select_type | table     | type | possible_keys | key  | key_len | ref  | rows   | Extra       |
+------+-------------+-----------+------+---------------+------+---------+------+--------+-------------+
|    1 | SIMPLE      | employees | ALL  | NULL          | NULL | NULL    | NULL | 299202 | Using where |
+------+-------------+-----------+------+---------------+------+---------+------+--------+-------------+
1 row in set (0.00 sec)

EXPLAIN
SELECT *
FROM   dept_emp d,employees e
WHERE  e.emp_no=d.emp_no AND d.dept_no IN ('d001','d002');

+------+-------------+-------+--------+-----------------+---------+---------+--------------------+--------+-------------+
| id   | select_type | table | type   | possible_keys   | key     | key_len | ref                | rows   | Extra       |
+------+-------------+-------+--------+-----------------+---------+---------+--------------------+--------+-------------+
|    1 | SIMPLE      | d     | ALL    | PRIMARY,dept_no | NULL    | NULL    | NULL               | 331570 | Using where |
|    1 | SIMPLE      | e     | eq_ref | PRIMARY         | PRIMARY | 4       | employees.d.emp_no |      1 |             |
+------+-------------+-------+--------+-----------------+---------+---------+--------------------+--------+-------------+
2 rows in set (0.00 sec)


4.3.11 EXPLAIN EXTENDED(Filtered 컬럼)


EXPLAIN EXTENDED
SELECT *
FROM   employees
WHERE  emp_no BETWEEN 10001 AND 10100 AND gender='F';

+------+-------------+-----------+-------+---------------+---------+---------+------+------+----------+-------------+
| id   | select_type | table     | type  | possible_keys | key     | key_len | ref  | rows | filtered | Extra       |
+------+-------------+-----------+-------+---------------+---------+---------+------+------+----------+-------------+
|    1 | SIMPLE      | employees | range | PRIMARY       | PRIMARY | 4       | NULL |  100 |   100.00 | Using where |
+------+-------------+-----------+-------+---------------+---------+---------+------+------+----------+-------------+
1 row in set, 1 warning (0.00 sec)


4.3.12 EXPLAIN EXTENDED(추가 옵티마이저 정보)


EXPLAIN EXTENDED
SELECT e.first_name,
  (SELECT COUNT(*) FROM dept_emp d, dept_manager m WHERE d.dept_no=m.dept_no) AS cnt
FROM   employees e
WHERE  e.emp_no=10001;

+------+-------------+-------+-------+---------------+---------+---------+---------------------+-------+----------+-------------+
| id   | select_type | table | type  | possible_keys | key     | key_len | ref                 | rows  | filtered | Extra       |
+------+-------------+-------+-------+---------------+---------+---------+---------------------+-------+----------+-------------+
|    1 | PRIMARY     | e     | const | PRIMARY       | PRIMARY | 4       | const               |     1 |   100.00 |             |
|    2 | SUBQUERY    | m     | index | dept_no       | dept_no | 4       | NULL                |    24 |   100.00 | Using index |
|    2 | SUBQUERY    | d     | ref   | dept_no       | dept_no | 4       | employees.m.dept_no | 20723 |   100.00 | Using index |
+------+-------------+-------+-------+---------------+---------+---------+---------------------+-------+----------+-------------+
3 rows in set, 1 warning (0.00 sec)

SHOW WARNINGS;

SELECT 'George' AS 'first_name'
FROM   'employees'.'employees' 'e' WHERE 1;

MariaDB [employees]> SHOW WARNINGS;
+-------+------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Level | Code | Message                                                                                                                                                                                 |
+-------+------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Error | 1064 | You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near ''employees'.'employees' 'e' WHERE 1' at line 2 |
+-------+------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+


4.3.13 EXPLAIN PARTITIONS(Partions 컬럼)


CREATE TABLE tb_partition (
  reg_date DATE DEFAULT NULL,
  id INT DEFAULT NULL,
  name VARCHAR(50) DEFAULT NULL) ENGINE=INNODB
  partition BY range(YEAR(reg_date)) (
    partition p0 VALUES less than (2008) ENGINE=INNODB,
    partition p1 VALUES less than (2009) ENGINE=INNODB,
    partition p2 VALUES less than (2010) ENGINE=INNODB,
    partition p3 VALUES less than (2011) ENGINE=INNODB
  );
  
  EXPLAIN PARTITIONS
  SELECT * FROM tb_partition
  WHERE  reg_date BETWEEN '2010-01-01' AND '2010-12-30' ;

+------+-------------+--------------+------------+------+---------------+------+---------+------+------+-------------+
| id   | select_type | table        | partitions | type | possible_keys | key  | key_len | ref  | rows | Extra       |
+------+-------------+--------------+------------+------+---------------+------+---------+------+------+-------------+
|    1 | SIMPLE      | tb_partition | p3         | ALL  | NULL          | NULL | NULL    | NULL |    2 | Using where |
+------+-------------+--------------+------------+------+---------------+------+---------+------+------+-------------+
1 row in set (0.00 sec)


4.4 옵티마이저 힌트

4.4.1 힌트의 사용법


SELECT * FROM employees USE_INDEX(primary) WHERE emp_no=10001;
SELECT * FROM employees /*! USE_INDEX(primary)*/ WHERE emp_no=10001;

CREATE /*!32302 TEMPOARY*/ TABLE temp_emp_stat
(hire_year INT NOT NULL, emp_count INT, PRIMARY KEY(hire_year));

CREATE TEMPOARY TABLE temp_emp_stat
(hire_year INT NOT NULL, emp_count INT, PRIMARY KEY(hire_year));


4.4.2 STRAIGHT_JOIN


EXPLAIN
SELECT /*! STRAIGHT_JOIN */
       e.first_name , e.last_name, d.dept_name
FROM   employees e, departments d, dept_emp de
WHERE  e.emp_no=de.emp_no AND d.dept_no=de.dept_no;


+------+-------------+-------+--------+-----------------+-----------+---------+----------------------------------------+--------+-------------------------------------------------+
| id   | select_type | table | type   | possible_keys   | key       | key_len | ref                                    | rows   | Extra                                           |
+------+-------------+-------+--------+-----------------+-----------+---------+----------------------------------------+--------+-------------------------------------------------+
|    1 | SIMPLE      | e     | ALL    | PRIMARY         | NULL      | NULL    | NULL                                   | 299202 |                                                 |
|    1 | SIMPLE      | d     | index  | PRIMARY         | dept_name | 42      | NULL                                   |      9 | Using index; Using join buffer (flat, BNL join) |
|    1 | SIMPLE      | de    | eq_ref | PRIMARY,dept_no | PRIMARY   | 8       | employees.e.emp_no,employees.d.dept_no |      1 | Using index                                     |
+------+-------------+-------+--------+-----------------+-----------+---------+----------------------------------------+--------+-------------------------------------------------+
3 rows in set (0.00 sec)


4.4.3 USE INDEX / FORCE INDEX / IGNORE INDEX


SELECT * FROM employees WHERE emp_no=10001;
SELECT * FROM employees FORCE INDEX(primary) WHERE emp_no=10001;
SELECT * FROM employees USE INDEX(primary) WHERE emp_no=10001;
SELECT * FROM employees IGNORE INDEX(primary) WHERE emp_no=10001;
SELECT * FROM employees FORCE INDEX(ix_firstname) WHERE emp_no=10001;


4.4.4 SQL_CACHE/SQL_NO_CACHE


SELECT COUNT(*) FROM employees WHERE last_name = 'Facello';

SELECT SQL_NO_CACHE COUNT(*) FROM employees WHERE last_name='Facello';
SELECT /*! SQL_NO_CACHE */ COUNT(*) FROM employees WHERE last_name='Facello'


4.4.5 SQL_CALC_FOUND_ROWS


SELECT SQL_CALC_FOUND_ROWS * FROM employees LIMIT 5;

MariaDB [employees]> SELECT SQL_CALC_FOUND_ROWS * FROM employees LIMIT 5;
+--------+------------+------------+-----------+--------+------------+
| emp_no | birth_date | first_name | last_name | gender | hire_date  |
+--------+------------+------------+-----------+--------+------------+
|  10001 | 1953-09-02 | Georgi     | Facello   | M      | 1986-06-26 |
|  10002 | 1964-06-02 | Bezalel    | Simmel    | F      | 1985-11-21 |
|  10003 | 1959-12-03 | Parto      | Bamford   | M      | 1986-08-28 |
|  10004 | 1954-05-01 | Chirstian  | Koblick   | M      | 1986-12-01 |
|  10005 | 1955-01-21 | Kyoichi    | Maliniak  | M      | 1989-09-12 |
+--------+------------+------------+-----------+--------+------------+
5 rows in set (0.22 sec)

MariaDB [employees]> SELECT FOUND_ROWS() AS total_record_count;
+--------------------+
| total_record_count |
+--------------------+
|             300024 |
+--------------------+
1 row in set (0.00 sec)