EXPLAIN для первого запроса показывает, что он выполняет сканирование таблицы (type=ALL
) из 300 тыс. Строк из employees
, а для каждого из них выполняет поиск частичного первичного ключа (type=ref
) до 1 строки ( по оценкам) в salaries
.
mysql> explain SELECT * FROM employees
INNER JOIN salaries ON employees.emp_no = salaries.emp_no;
+----+-------------+-----------+------+---------------+---------+---------+----------------------------+--------+-------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-----------+------+---------------+---------+---------+----------------------------+--------+-------+
| 1 | SIMPLE | employees | ALL | PRIMARY | NULL | NULL | NULL | 299113 | NULL |
| 1 | SIMPLE | salaries | ref | PRIMARY | PRIMARY | 4 | employees.employees.emp_no | 1 | NULL |
+----+-------------+-----------+------+---------------+---------+---------+----------------------------+--------+-------+
Объяснение для второго запроса (на самом деле разумный запрос для вычисления AVG (), как вы упомянули в комментарии), показывает нечто дополнительное:
mysql> EXPLAIN SELECT employees.gender, AVG(salary) FROM employees
INNER JOIN salaries ON employees.emp_no = salaries.emp_no
GROUP BY employees.gender;
+----+-------------+-----------+------+---------------+---------+---------+----------------------------+--------+---------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-----------+------+---------------+---------+---------+----------------------------+--------+---------------------------------+
| 1 | SIMPLE | employees | ALL | PRIMARY | NULL | NULL | NULL | 299113 | Using temporary; Using filesort |
| 1 | SIMPLE | salaries | ref | PRIMARY | PRIMARY | 4 | employees.employees.emp_no | 1 | NULL |
+----+-------------+-----------+------+---------------+---------+---------+----------------------------+--------+---------------------------------+
См. Using temporary; Using filesort
в поле Extra? Это означает, что запрос должен создать временную таблицу для накопления результатов AVG () для каждой группы. Он должен использовать временную таблицу, потому что MySQL не может знать, что он будет сканировать все строки для каждого пола вместе, поэтому он должен предположить, что ему нужно будет поддерживать промежуточные итоги независимо, так как он сканирует строки. Не похоже, что будет большой проблемой отследить два (в данном случае) половых числа, но предположим, что это был почтовый индекс или что-то в этом роде?
Создание временной таблицы - довольно дорогая операция. Это означает запись данных, а не только чтение их, как это делает первый запрос.
Если бы мы могли создать индекс, упорядоченный по полу, тогда оптимизатор MySQL знал бы, что он может сканировать все эти строки с одним и тем же полом вместе. Таким образом, он может вычислять итоговую сумму одного пола за раз, затем, как только он завершит сканирование одного пола, рассчитает AVG (зарплату) и затем будет гарантировано, что дальнейшие строки для этого пола не будут сканироваться. Поэтому он может пропустить создание временной таблицы.
Этот индекс помогает:
mysql> alter table employees add index (gender, emp_no);
Теперь EXPLAIN того же запроса показывает, что он выполнит сканирование индекса (type=index
), которое посещает то же количество записей, но будет сканировать в более полезном порядке для вычисления совокупности AVG (). .
Тот же запрос, но нет Using temporary
Примечание:
mysql> EXPLAIN SELECT employees.gender, AVG(salary) FROM employees
INNER JOIN salaries ON employees.emp_no = salaries.emp_no
GROUP BY employees.gender;
+----+-------------+-----------+-------+----------------+---------+---------+----------------------------+--------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-----------+-------+----------------+---------+---------+----------------------------+--------+-------------+
| 1 | SIMPLE | employees | index | PRIMARY,gender | gender | 5 | NULL | 299113 | Using index |
| 1 | SIMPLE | salaries | ref | PRIMARY | PRIMARY | 4 | employees.employees.emp_no | 1 | NULL |
+----+-------------+-----------+-------+----------------+---------+---------+----------------------------+--------+-------------+
И выполнение этого запроса намного быстрее:
+--------+-------------+
| gender | AVG(salary) |
+--------+-------------+
| M | 63838.1769 |
| F | 63769.6032 |
+--------+-------------+
2 rows in set (1.06 sec)