2010-05-05 3 views
3

employees database을 다운로드하고 벤치마킹을 위해 쿼리를 실행했습니다.
그런 다음 이전에 생성 한 해당 색인이 있지만 하나의 쿼리에서 커버 인덱스를 사용하지 않은 것으로 나타났습니다. 쿼리에 FORCE INDEX 절을 추가 한 경우에만 에 덮음 인덱스이 사용되었습니다.
두 파일을 업로드했습니다. 하나는 the executed SQL queries이고 다른 하나는 the results입니다.
FORCE INDEX 절이 추가 된 경우에만 쿼리에서 커버 인덱스를 사용하는 이유를 알 수 있습니까? EXPLAIN은 두 경우 모두 인덱스 dept_no_from_date_idx이 어쨌든 사용되고 있음을 보여줍니다.해당하는 경우 쿼리에서 커버 인덱스를 사용하지 않습니다.

는 SQL 쿼리 :

USE employees; 

/* Creating an index for an index-covered query */ 
    CREATE INDEX dept_no_from_date_idx ON dept_emp (dept_no, from_date); 

/* Show `dept_emp` table structure, indexes and generic data */ 
    SHOW TABLE STATUS LIKE "dept_emp"; 
    DESCRIBE dept_emp; 
    SHOW KEYS IN dept_emp; 

/* The EXPLAIN shows that the subquery doesn't use a covering-index */ 
EXPLAIN SELECT SQL_NO_CACHE * FROM dept_emp INNER JOIN (
     /* The subquery should use a covering index, but isn't */ 
     SELECT SQL_NO_CACHE emp_no, dept_no FROM dept_emp WHERE dept_no="d001" ORDER BY from_date DESC LIMIT 20000,50 
    ) AS `der` USING (`emp_no`, `dept_no`); 

/* The EXPLAIN shows that the subquery DOES use a covering-index, 
     thanks to the FORCE INDEX clause */ 
EXPLAIN SELECT SQL_NO_CACHE * FROM dept_emp INNER JOIN (
     /* The subquery use a covering index */ 
     SELECT SQL_NO_CACHE emp_no, dept_no FROM dept_emp FORCE INDEX(dept_no_from_date_idx) WHERE dept_no="d001" ORDER BY from_date DESC LIMIT 20000,50 
    ) AS `der` USING (`emp_no`, `dept_no`); 

결과 :

나는 여기 두 파일의 내용을 쓰고 있어요, SO의 기준에 자신을 적응
-------------- 
/* Creating an index for an index-covered query */ 
    CREATE INDEX dept_no_from_date_idx ON dept_emp (dept_no, from_date) 
-------------- 

Query OK, 331603 rows affected (33.95 sec) 
Records: 331603 Duplicates: 0 Warnings: 0 

-------------- 
/* Show `dept_emp` table structure, indexes and generic data */ 
    SHOW TABLE STATUS LIKE "dept_emp" 
-------------- 

+----------+--------+---------+------------+--------+----------------+-------------+-----------------+--------------+-----------+----------------+---------------------+-------------+------------+-----------------+----------+----------------+---------+ 
| Name  | Engine | Version | Row_format | Rows | Avg_row_length | Data_length | Max_data_length | Index_length | Data_free | Auto_increment | Create_time   | Update_time | Check_time | Collation  | Checksum | Create_options | Comment | 
+----------+--------+---------+------------+--------+----------------+-------------+-----------------+--------------+-----------+----------------+---------------------+-------------+------------+-----------------+----------+----------------+---------+ 
| dept_emp | InnoDB |  10 | Compact | 331883 |    36 | 12075008 |    0 |  21544960 | 29360128 |   NULL | 2010-05-04 13:07:49 | NULL  | NULL  | utf8_general_ci |  NULL |    |   | 
+----------+--------+---------+------------+--------+----------------+-------------+-----------------+--------------+-----------+----------------+---------------------+-------------+------------+-----------------+----------+----------------+---------+ 
1 row in set (0.47 sec) 

-------------- 
    DESCRIBE dept_emp 
-------------- 

+-----------+---------+------+-----+---------+-------+ 
| Field  | Type | Null | Key | Default | Extra | 
+-----------+---------+------+-----+---------+-------+ 
| emp_no | int(11) | NO | PRI | NULL |  | 
| dept_no | char(4) | NO | PRI | NULL |  | 
| from_date | date | NO |  | NULL |  | 
| to_date | date | NO |  | NULL |  | 
+-----------+---------+------+-----+---------+-------+ 
4 rows in set (0.05 sec) 

-------------- 
    SHOW KEYS IN dept_emp 
-------------- 

+----------+------------+-----------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+ 
| Table | Non_unique | Key_name    | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | 
+----------+------------+-----------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+ 
| dept_emp |   0 | PRIMARY    |   1 | emp_no  | A   |  331883 |  NULL | NULL |  | BTREE  |   | 
| dept_emp |   0 | PRIMARY    |   2 | dept_no  | A   |  331883 |  NULL | NULL |  | BTREE  |   | 
| dept_emp |   1 | emp_no    |   1 | emp_no  | A   |  331883 |  NULL | NULL |  | BTREE  |   | 
| dept_emp |   1 | dept_no    |   1 | dept_no  | A   |   7 |  NULL | NULL |  | BTREE  |   | 
| dept_emp |   1 | dept_no_from_date_idx |   1 | dept_no  | A   |   13 |  NULL | NULL |  | BTREE  |   | 
| dept_emp |   1 | dept_no_from_date_idx |   2 | from_date | A   |  165941 |  NULL | NULL |  | BTREE  |   | 
+----------+------------+-----------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+ 
6 rows in set (0.23 sec) 

-------------- 
/* The EXPLAIN shows that the subquery doesn't use a covering-index */ 
EXPLAIN SELECT SQL_NO_CACHE * FROM dept_emp INNER JOIN (
     /* The subquery should use a covering index, but isn't */ 
     SELECT SQL_NO_CACHE emp_no, dept_no FROM dept_emp WHERE dept_no="d001" ORDER BY from_date DESC LIMIT 20000,50 
    ) AS `der` USING (`emp_no`, `dept_no`) 
-------------- 

+----+-------------+------------+--------+----------------------------------------------+-----------------------+---------+------------------------+-------+-------------+ 
| id | select_type | table  | type | possible_keys        | key     | key_len | ref     | rows | Extra  | 
+----+-------------+------------+--------+----------------------------------------------+-----------------------+---------+------------------------+-------+-------------+ 
| 1 | PRIMARY  | <derived2> | ALL | NULL           | NULL     | NULL | NULL     | 50 |    | 
| 1 | PRIMARY  | dept_emp | eq_ref | PRIMARY,emp_no,dept_no,dept_no_from_date_idx | PRIMARY    | 16  | der.emp_no,der.dept_no |  1 |    | 
| 2 | DERIVED  | dept_emp | ref | dept_no,dept_no_from_date_idx    | dept_no_from_date_idx | 12  |      | 21402 | Using where | 
+----+-------------+------------+--------+----------------------------------------------+-----------------------+---------+------------------------+-------+-------------+ 
3 rows in set (0.09 sec) 

-------------- 
/* The EXPLAIN shows that the subquery DOES use a covering-index, 
     thanks to the FORCE INDEX clause */ 
EXPLAIN SELECT SQL_NO_CACHE * FROM dept_emp INNER JOIN (
     /* The subquery use a covering index */ 
     SELECT SQL_NO_CACHE emp_no, dept_no FROM dept_emp FORCE INDEX(dept_no_from_date_idx) WHERE dept_no="d001" ORDER BY from_date DESC LIMIT 20000,50 
    ) AS `der` USING (`emp_no`, `dept_no`) 
-------------- 

+----+-------------+------------+--------+----------------------------------------------+-----------------------+---------+------------------------+-------+--------------------------+ 
| id | select_type | table  | type | possible_keys        | key     | key_len | ref     | rows | Extra     | 
+----+-------------+------------+--------+----------------------------------------------+-----------------------+---------+------------------------+-------+--------------------------+ 
| 1 | PRIMARY  | <derived2> | ALL | NULL           | NULL     | NULL | NULL     | 50 |       | 
| 1 | PRIMARY  | dept_emp | eq_ref | PRIMARY,emp_no,dept_no,dept_no_from_date_idx | PRIMARY    | 16  | der.emp_no,der.dept_no |  1 |       | 
| 2 | DERIVED  | dept_emp | ref | dept_no_from_date_idx      | dept_no_from_date_idx | 12  |      | 37468 | Using where; Using index | 
+----+-------------+------------+--------+----------------------------------------------+-----------------------+---------+------------------------+-------+--------------------------+ 
3 rows in set (0.05 sec) 

Bye 

편집 : 나는 실행 순서를 변경하는 경우 (마지막을,

SELECT SQL_NO_CACHE * FROM dept_emp INNER JOIN (
    SELECT SQL_NO_CACHE emp_no, dept_no FROM dept_emp WHERE dept_no="d001" ORDER BY from_date DESC LIMIT 20000,50 
) AS `der` USING (`emp_no`, `dept_no`) 
-------------- 

+--------+---------+------------+------------+ 
| emp_no | dept_no | from_date | to_date | 
+--------+---------+------------+------------+ 
| 38552 | d001 | 1985-04-16 | 2000-10-20 | 
      ... omitted ... 
| 98045 | d001 | 1985-03-28 | 9999-01-01 | 
+--------+---------+------------+------------+ 
50 rows in set (0.31 sec) 

-------------- 
SELECT SQL_NO_CACHE * FROM dept_emp INNER JOIN (
    SELECT SQL_NO_CACHE emp_no, dept_no FROM dept_emp FORCE INDEX(dept_no_from_date_idx) WHERE dept_no="d001" ORDER BY from_date DESC LIMIT 20000,50 
) AS `der` USING (`emp_no`, `dept_no`) 
-------------- 

+--------+---------+------------+------------+ 
| emp_no | dept_no | from_date | to_date | 
+--------+---------+------------+------------+ 
| 38552 | d001 | 1985-04-16 | 2000-10-20 | 
      ... omitted ... 
| 98045 | d001 | 1985-03-28 | 9999-01-01 | 
+--------+---------+------------+------------+ 
50 rows in set (0.06 sec) 

을하지만 :
나는 마지막 두 쿼리 사이에 매우 중요한 실행 속도의 차이가 결과가 전에 배치가 있다는 것을 발견 조회 후, 실행 속도가 동일) 제 실행되는, 제 1 질의 마지막 실행될 :

-------------- 
SELECT SQL_NO_CACHE * FROM dept_emp INNER JOIN (
    SELECT SQL_NO_CACHE emp_no, dept_no FROM dept_emp FORCE INDEX(dept_no_from_date_idx) WHERE dept_no="d001" ORDER BY from_date DESC LIMIT 20000,50 
) AS `der` USING (`emp_no`, `dept_no`) 
-------------- 

+--------+---------+------------+------------+ 
| emp_no | dept_no | from_date | to_date | 
+--------+---------+------------+------------+ 
| 38552 | d001 | 1985-04-16 | 2000-10-20 | 
      ... omitted ... 
| 98045 | d001 | 1985-03-28 | 9999-01-01 | 
+--------+---------+------------+------------+ 
50 rows in set (0.08 sec) 

-------------- 
SELECT SQL_NO_CACHE * FROM dept_emp INNER JOIN (
    SELECT SQL_NO_CACHE emp_no, dept_no FROM dept_emp WHERE dept_no="d001" ORDER BY from_date DESC LIMIT 20000,50 
) AS `der` USING (`emp_no`, `dept_no`) 
-------------- 

+--------+---------+------------+------------+ 
| emp_no | dept_no | from_date | to_date | 
+--------+---------+------------+------------+ 
| 38552 | d001 | 1985-04-16 | 2000-10-20 | 
      ... omitted ... 
| 98045 | d001 | 1985-03-28 | 9999-01-01 | 
+--------+---------+------------+------------+ 
50 rows in set (0.08 sec) 

그것은 제 2 질의가 그 SQL_NO_CACHE 때문에, 캐시에서 수행 될 수 없다는 두 쿼리 모두에 기록됩니다. 첫 번째 예제에서 첫 번째 쿼리는 0.31 초, 두 번째 예제에서는 0.06 초가 걸렸지 만 두 번째 예제에서는 두 쿼리 모두 0.08 초가 걸렸습니다.

Edit2가 :
나는 실행 속도의 차이는 OS 캐시와 아마 다른 요인에서 유래한다고 생각합니다. 위의 2 개의 쿼리를 반복적으로 실행하면 실행 시간 차이가 무시됩니다. 위의 2 개의 쿼리를 3 번 ​​반복 실행하여 다음 결과를 얻었습니다.

#1: 0.08 sec 
#2: 0.03 sec 
#1: 0.05 sec 
#2: 0.05 sec 
#1: 0.03 sec 
#2: 0.05 sec 
+0

제출 된 버그 보고서 : http://bugs.mysql.com/bug.php?id=53442 – Dor

답변

2

실제로 두 쿼리 모두 커버 인덱스를 사용합니다.

색인 정의에 emp_no이 포함되어 있지 않으므로 절을 사용하는 경우에도 MyISAMUsing index을 사용할 수 없습니다.

그러나, InnoDB 테이블은 클러스터되고 모든 인덱스는 암시 적으로 레코드 포인터로 PRIMARY KEY을 포함합니다.

이것은 색인이 사실 (dept_no, from_date, emp_no, dept_no)의 색인이므로 필요한 모든 입력란이 포함되어 있음을 의미합니다.

EXPLAIN PLAN이 항상이 내용을 올바르게 반영하는 것은 아니지만 InnoDB 엔진이이를 처리합니다.

이러한 두 개의 쿼리의 성능을 비교하여 확인할 수 있습니다

SELECT SQL_NO_CACHE * FROM dept_emp INNER JOIN (
     /* The subquery use a covering index */ 
     SELECT SQL_NO_CACHE from_date, emp_no, dept_no FROM dept_emp WHERE dept_no="d001" ORDER BY from_date DESC LIMIT 20000,50 
    ) AS `der` USING (`emp_no`, `dept_no`); 

SELECT SQL_NO_CACHE * FROM dept_emp INNER JOIN (
     /* The subquery use a covering index */ 
     SELECT SQL_NO_CACHE to_date, emp_no, dept_no FROM dept_emp WHERE dept_no="d001" ORDER BY from_date DESC LIMIT 20000,50 
    ) AS `der` USING (`emp_no`, `dept_no`); 

당신은 볼 것이다 계획이 동일로 표시됩니다 있다는 사실에도 불구하고, 두 번째 쿼리 (to_date이 적용되지 않기 때문에) 더 많은 시간이 소요됩니다.

InnoDB 엔진이 아닌 EXPLAIN PLAN의 버그입니다.

+0

실제로 큰 차이가있었습니다. 첫 번째 쿼리에는 0.25 초가 걸렸고 두 번째 쿼리에는 2.17 초가 걸렸습니다. 나는 InnoDB의 구조 등에 익숙하다. mysql.com에서 버그 보고서를 찾고 있는데 찾을 수 없다. 보고서가 어디 있는지 아십니까? 감사합니다 :) – Dor

+0

@dor : http://bugs.mysql.com/report.php – Quassnoi

+0

당신은 ** 내가 **이 버그에 대해보고해야한다는 것을 의미합니까? 지금까지 아무도 눈치 채지 못했습니까? Neat = D – Dor