Всем известно, что mysql выполняет оптимизацию запросов при выполнении запроса. Проще говоря, при выполненииОптимизация на основе стоимости и правилгенерироватьПлан реализации, а затем выполнить запрос в соответствии с планом выполнения. Эта статья в основном знакомитEXPLAIN
Значение каждого элемента вывода, чтобы помочь всем лучшеОптимизация производительности SQL!
Основное содержание этой статьи основано на буклете Nuggets «Понимание MySQL с самого начала». Если вы хотите узнать больше, рекомендуется купить буклет Nuggets для чтения.
Мы можем добавить перед оператором запросаEXPLAIN
ключевые слова для просмотра этого запросаПлан реализации. Например
mysql> EXPLAIN SELECT 1;
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+----------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+----------------+
| 1 | SIMPLE | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | No tables used |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+----------------+
1 row in set, 1 warning (0.01 sec)
Как видите, план выполнения содержит много выходных столбцов.Давайте сначала кратко объясним общую функцию каждого столбца, а затем объясним его подробно.
имя столбца | описывать |
---|---|
id | В большом операторе запроса каждыйSELECT Каждому ключевому слову соответствует уникальный идентификатор |
select_type |
SELECT Тип запроса, которому соответствует ключевое слово |
table | Имя таблицы |
partitions | совпадающая информация о разделе |
type | Метод доступа к одной таблице |
possible_keys | возможные индексы |
key | фактически используемый индекс |
key_len | Фактическая длина используемого индекса |
ref | При использовании запроса эквивалентности столбца индекса информация об объекте, которая эквивалентно соответствует столбцу индекса |
rows | Предполагаемое количество записей для чтения |
filtered | Процент оставшихся записей после фильтрации таблицы по критериям поиска |
Extra | некоторая дополнительная информация |
Предварительно релевантные очки знаний
Чтобы подробно понять значение каждого столбца плана выполнения, мы должны сначала понять следующие связанные точки знаний.
некоррелированный подзапрос
еслиподзапросРезультаты можно запускать независимо, не полагаясь на внешний запрос, мы называем этот подзапроснекоррелированный подзапрос.
коррелированные подзапросы
Если выполнение подзапроса зависит от значений внешнего запроса, мы вызываем подзапроскоррелированные подзапросы.
Материализация подзапроса
Вместо того, чтобы напрямую обрабатывать набор результатов некоррелированного подзапроса как параметр внешнего запроса, запишите набор результатов во временную таблицу (материализованную таблицу).. Например:
SELECT * FROM s1 WHERE key1 IN (SELECT common_field FROM s2 WHERE key3 = 'a');
Предположим, что имя материализованной таблицы подзапросаmaterialized_table
, столбец результирующего набора подзапроса, хранящийся в материализованной таблице, имеет видm_val
. После материализации подзапросастол может бытьs1
и материализованная таблица подзапросовmaterialized_table
Операция внутреннего соединения, а затем получите соответствующий результат запроса.
SELECT s1.* FROM s1 INNER JOIN materialized_table ON key1 = m_val;
Преобразование подзапроса в полусоединение
После материализации подзапроса и последующего выполнения запроса будут затраты на создание временной таблицы.Можно ли напрямую преобразовать подзапрос в соединение без его материализации? Вернемся к запросу выше:
SELECT * FROM s1 WHERE key1 IN (SELECT common_field FROM s2 WHERE key3 = 'a');
Мы можем понять этот запрос как:заs1
Запись в таблице, если мы можемs2
стол (точнее, после выполненияWHERE s2.key3 = 'a'
последующий набор результатов) найдено одно или несколько совпаденийs2.common_field=s1.key1
записи, тоs1
Записи таблицы будут добавлены в окончательный набор результатов.. На самом деле этот процессs1
иs2
Эффект объединения двух таблиц очень похож:
SELECT s1.* FROM s1 INNER JOIN s2 ON s1.key1 = s2.common_field WHERE s2.key3 = 'a';
Единственная проблема заключается в том, что дляs1
Для записи в таблице, еслиs2
таблица имеетнесколько записейудовлетворитьs1.key1 = s2.common_field
Это условие, затем запись будет добавлена в окончательный набор результатов несколько раз, поэтомуЭти два нельзя считать полностью эквивалентными, так что естьsemi-join
(полусвязный). будетs1
стол иs2
Полусоединение таблиц означает:заs1
Для записи в таблице нас интересует толькоs2
Если в таблице есть совпадающая запись, независимо от того, сколько записей ей соответствует, окончательный набор результатов сохраняет толькоs1
записи таблицы. Конечноsemi-join
Это внутренний механизм mysql, и его нельзя использовать непосредственно в операторах sql.
механизм реализации полусоединения
Вывод таблицы (вывод таблицы в подзапросах)
Когда список запросов подзапросаТолько столбцы первичного ключа или уникального индекса, вы можете напрямую вытащить таблицу из подзапроса во внешний запросFROM
и объедините условия поиска в подзапросе с условиями поиска внешнего запроса, например:
SELECT * FROM s1 WHERE key2 IN (SELECT key2 FROM s2 WHERE key3 = 'a');
так какkey2
столбецs2
Единственный столбец вторичного индекса таблицы, поэтому мы можем напрямую поместитьs2
Таблица подтягивается к внешнему запросуFROM
предложение и объединить условия поиска в подзапросе с условиями поиска внешнего запроса, по сути, напрямую оптимизировать подзапрос в запрос на соединение.Запрос после подтягивания выглядит следующим образом:
SELECT s1.* FROM s1 INNER JOIN s2 ON s1.key2 = s2.key2 WHERE s2.key3 = 'a';
Стратегия выполнения DuplicateWeedout
Например, следующий запрос:
SELECT * FROM s1 WHERE key1 IN (SELECT common_field FROM s2 WHERE key3 = 'a');
После преобразования в запрос полуобъединенияs1
Запись в таблице может быть вs2
В таблице есть несколько совпадающих записей, поэтому запись может быть добавлена в окончательный набор результатов несколько раз. Чтобы исключить дублирование, мы можем создать временную таблицу, например, эта временная таблица выглядит так:
CREATE TABLE tmp (
id PRIMARY KEY
);
Таким образом, в процессе выполнения запроса на соединение всякий раз, когда запись в таблице s1 должна быть добавлена к набору результатов, значение идентификатора записи сначала добавляется во временную таблицу. Такое использование временных таблиц устраняетsemi-join
Как называются повторяющиеся значения в результирующем набореDuplicateWeedout
.
Стратегия выполнения LooseScan
Например, следующий запрос:
SELECT * FROM s1 WHERE key3 IN (SELECT key1 FROM s2 WHERE key1 > 'a' AND key1 < 'b');
В подзапросе дляs2
Доступ к таблице можно сделать с помощьюkey1
Индекс столбца, который находится в списке запросов подзапроса, равенkey1
столбец, так что после преобразования запроса в запрос полуобъединения, еслиs2
Если запрос выполняется как управляющая таблица, то процесс выполнения выглядит следующим образом:Как показано на рисунке, вs2
Таблицаidx_key1
В индексе значение'aa'
Всего в каталоге есть 3 записи вторичного индекса.s1.key3 = 'aa'
записи, если таковые имеются вs1
Если соответствующая запись найдена в таблице, то соответствующая запись добавляется в набор результатов.Несмотря на то, что это индекс сканирования, только первая запись с тем же значением используется для операций сопоставления, что называется свободным сканированием.
Стратегия исполнения FirstMatch
FirstMatch
Это самый примитивный метод выполнения semi-join. Короче говоря, это означает сначала взять запись во внешнем запросе, а затем перейти к таблице подзапроса, чтобы найти запись, которая удовлетворяет условиям соответствия. Если она может быть найдена, то внешний запрос Поместите запрошенные записи в окончательный набор результатов и прекратите поиск других совпадающих записей.Если они не будут найдены, отбросьте записи внешнего запроса, затем начните извлекать записи в следующем внешнем запросе и повторите описанный выше процесс.
Подробный план реализации
Чтобы подробно объяснить значение каждого столбца плана выполнения, сначала постройте две таблицы-примера.s1
иs2
, структура их таблиц точно такая же.
CREATE TABLE s1 (
id INT NOT NULL AUTO_INCREMENT,
key1 VARCHAR(100),
key2 INT,
key3 VARCHAR(100),
key_part1 VARCHAR(100),
key_part2 VARCHAR(100),
key_part3 VARCHAR(100),
common_field VARCHAR(100),
PRIMARY KEY (id),
KEY idx_key1 (key1),
UNIQUE KEY idx_key2 (key2),
KEY idx_key3 (key3),
KEY idx_key_part(key_part1, key_part2, key_part3)
) Engine=InnoDB CHARSET=utf8;
table
Независимо от того, насколько сложен наш оператор запроса и сколько таблиц включено в него, в конце нам нужно выполнить однотабличный доступ к каждой таблице, поэтомуКаждая запись, выводимая оператором EXPLAIN, соответствует методу доступа к отдельной таблице.. один из нихtable
Столбец представляет имя таблицы таблицы. Например:
mysql> EXPLAIN SELECT * FROM s1;
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------+
| 1 | SIMPLE | s1 | NULL | ALL | NULL | NULL | NULL | NULL | 9688 | 100.00 | NULL |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------+
1 row in set, 1 warning (0.00 sec)
Приведенный выше запрос включает только запрос одной таблицы, поэтомуEXPLAIN
Выводилась только одна запись.table
Значение столбцаs1
, что указывает на то, что запись описываетправильноs1
метод доступа к таблице.
Давайте посмотрим на план выполнения запроса на соединение:
mysql> EXPLAIN SELECT * FROM s1 INNER JOIN s2;
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+---------------------------------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+---------------------------------------+
| 1 | SIMPLE | s1 | NULL | ALL | NULL | NULL | NULL | NULL | 9688 | 100.00 | NULL |
| 1 | SIMPLE | s2 | NULL | ALL | NULL | NULL | NULL | NULL | 9954 | 100.00 | Using join buffer (Block Nested Loop) |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+---------------------------------------+
2 rows in set, 1 warning (0.01 sec)
можно увидеть,EXPLAIN
Выводятся только две записи.table
Значение столбцаs1
иs2
, соответственно представляющиеправильноs1
стол иs2
метод доступа к таблице.
id
Как мы все знаем, оператор запроса обычно содержит один или несколькоselect
ключевые слова. Можно просто предположить, что,Каждый раз, когда появляется оператор запросаselect
ключевое слово, в плане выполнения будет соответствующее значение id. Например, в приведенном ниже запросе есть только одинSELECT
Ключевые слова:
mysql> EXPLAIN SELECT * FROM s1 WHERE key1 = 'a';
+----+-------------+-------+------------+------+---------------+----------+---------+-------+------+----------+-------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+------+---------------+----------+---------+-------+------+----------+-------+
| 1 | SIMPLE | s1 | NULL | ref | idx_key1 | idx_key1 | 303 | const | 8 | 100.00 | NULL |
+----+-------------+-------+------------+------+---------------+----------+---------+-------+------+----------+-------+
1 row in set, 1 warning (0.03 sec)
Для запросов на соединениеselect
Часто запрашивается несколько таблиц, поэтому в плане выполнения будет несколько записей, но ихid
все так же. Среди них таблица, которая появляется впереди, является ведущей, а таблица, которая появляется сзади, — ведомой таблицей.
mysql> EXPLAIN SELECT * FROM s1 INNER JOIN s2;
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+---------------------------------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+---------------------------------------+
| 1 | SIMPLE | s1 | NULL | ALL | NULL | NULL | NULL | NULL | 9688 | 100.00 | NULL |
| 1 | SIMPLE | s2 | NULL | ALL | NULL | NULL | NULL | NULL | 9954 | 100.00 | Using join buffer (Block Nested Loop) |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+---------------------------------------+
2 rows in set, 1 warning (0.01 sec)
Для подзапросов он может содержать несколькоselect
ключевые слова, каждыйselect
Ключевое слово будет соответствовать уникальному значению идентификатора.
mysql> EXPLAIN SELECT * FROM s1 WHERE key1 IN (SELECT key1 FROM s2) OR key3 = 'a';
+----+-------------+-------+------------+-------+---------------+----------+---------+------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+-------+---------------+----------+---------+------+------+----------+-------------+
| 1 | PRIMARY | s1 | NULL | ALL | idx_key3 | NULL | NULL | NULL | 9688 | 100.00 | Using where |
| 2 | SUBQUERY | s2 | NULL | index | idx_key1 | idx_key1 | 303 | NULL | 9954 | 100.00 | Using index |
+----+-------------+-------+------------+-------+---------------+----------+---------+------+------+----------+-------------+
2 rows in set, 1 warning (0.02 sec)
Но есть еще одно замечание:Оптимизатор запросов может переписывать запросы, включающие подзапросы, в запросы на соединение.. В этот момент значение идентификатора плана выполнения остается прежним.
для содержанияunion
Для запросов по ключевым словам, в дополнение к каждомуselect
Ключевое слово соответствует значению идентификатора и также будет содержатьid
значениеNULL
запись о. Эта запись в основном используется для дедупликации результирующего набора двух запросов (union all
Потому что нет необходимости в дедупликации, нет такой записи).
mysql> EXPLAIN SELECT * FROM s1 UNION SELECT * FROM s2;
+----+--------------+------------+------------+------+---------------+------+---------+------+------+----------+-----------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+--------------+------------+------------+------+---------------+------+---------+------+------+----------+-----------------+
| 1 | PRIMARY | s1 | NULL | ALL | NULL | NULL | NULL | NULL | 9688 | 100.00 | NULL |
| 2 | UNION | s2 | NULL | ALL | NULL | NULL | NULL | NULL | 9954 | 100.00 | NULL |
| NULL | UNION RESULT | <union1,2> | NULL | ALL | NULL | NULL | NULL | NULL | NULL | NULL | Using temporary |
+----+--------------+------------+------------+------+---------------+------+---------+------+------+----------+-----------------+
3 rows in set, 1 warning (0.00 sec)
select_type
Мы уже знаем, что каждыйselect
все ключевые слова представляют небольшой запрос, аselect_type
Атрибуты используются для описания значения текущего небольшого запроса.select_type
Значение атрибута (выраженное непосредственно на английском языке на официальном сайте) следующее:
название | описывать |
---|---|
SIMPLE | Simple SELECT (not using UNION or subqueries) |
PRIMARY | Outermost SELECT |
UNION | Second or later SELECT statement in a UNION |
UNION RESULT | Result of a UNION |
SUBQUERY | First SELECT in subquery |
DEPENDENT SUBQUERY | First SELECT in subquery, dependent on outer query |
DEPENDENT UNION | Second or later SELECT statement in a UNION, dependent on outer query |
DERIVED | Derived table |
MATERIALIZED | Materialized subquery |
UNCACHEABLE SUBQUERY | A subquery for which the result cannot be cached and must be re-evaluated for each row of the outer query |
UNCACHEABLE UNION | The second or later select in a UNION that belongs to an uncacheable subquery (see UNCACHEABLE SUBQUERY) |
SIMPLE
оператор запроса не содержитUNION
или子查询
запросы считаютсяSIMPLE
Типы, такие как общие запросы к одной таблице и запросы на соединение.
PRIMARY
для содержанияUNION
,UNION ALL
или子查询
Для большого запроса он состоит из нескольких маленьких запросов, крайний левый из которыхselect_type
значениеPRIMARY
,Например:
mysql> EXPLAIN SELECT * FROM s1 UNION SELECT * FROM s2;
+----+--------------+------------+------------+------+---------------+------+---------+------+------+----------+-----------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+--------------+------------+------------+------+---------------+------+---------+------+------+----------+-----------------+
| 1 | PRIMARY | s1 | NULL | ALL | NULL | NULL | NULL | NULL | 9688 | 100.00 | NULL |
| 2 | UNION | s2 | NULL | ALL | NULL | NULL | NULL | NULL | 9954 | 100.00 | NULL |
| NULL | UNION RESULT | <union1,2> | NULL | ALL | NULL | NULL | NULL | NULL | NULL | NULL | Using temporary |
+----+--------------+------------+------------+------+---------------+------+---------+------+------+----------+-----------------+
3 rows in set, 1 warning (0.00 sec)
UNION
для содержанияUNION
илиUNION ALL
Для большого запроса он состоит из нескольких небольших запросов, из которых, кроме самого левого маленького запроса, остальныеselect_type
значениеUNION
.
UNION RESULT
MySQL
Возможность использовать временную таблицу для завершенияUNION
Работа по дедупликации запроса, запрос к временной таблицеselect_type
этоUNION RESULT
.
SUBQUERY
Если оператор запроса, содержащий подзапрос, не может быть преобразован в соответствующийsemi-join
, а подзапрос является некоррелированным подзапросом, и оптимизатор запросов решает использоватьМатериализация подзапросасхема выполнения подзапроса, первый подзапросSELECT
запрос, представленный ключевым словомselect_type
этоSUBQUERY
, например следующий запрос:
mysql> EXPLAIN SELECT * FROM s1 WHERE key1 IN (SELECT key1 FROM s2) OR key3 = 'a';
+----+-------------+-------+------------+-------+---------------+----------+---------+------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+-------+---------------+----------+---------+------+------+----------+-------------+
| 1 | PRIMARY | s1 | NULL | ALL | idx_key3 | NULL | NULL | NULL | 9688 | 100.00 | Using where |
| 2 | SUBQUERY | s2 | NULL | index | idx_key1 | idx_key1 | 303 | NULL | 9954 | 100.00 | Using index |
+----+-------------+-------+------------+-------+---------------+----------+---------+------+------+----------+-------------+
2 rows in set, 1 warning (0.00 sec)
DEPENDENT SUBQUERY
Если оператор запроса, содержащий подзапрос, не может быть преобразован в соответствующийsemi-join
, а подзапрос является коррелированным подзапросом, то первый подзапросSELECT
запрос, представленный ключевым словомselect_type
этоDEPENDENT SUBQUERY
, например следующий запрос:
mysql> EXPLAIN SELECT * FROM s1 WHERE key1 IN (SELECT key1 FROM s2 WHERE s1.key2 = s2.key2) OR key3 = 'a';
+----+--------------------+-------+------------+------+-------------------+----------+---------+-------------------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+--------------------+-------+------------+------+-------------------+----------+---------+-------------------+------+----------+-------------+
| 1 | PRIMARY | s1 | NULL | ALL | idx_key3 | NULL | NULL | NULL | 9688 | 100.00 | Using where |
| 2 | DEPENDENT SUBQUERY | s2 | NULL | ref | idx_key2,idx_key1 | idx_key2 | 5 | xiaohaizi.s1.key2 | 1 | 10.00 | Using where |
+----+--------------------+-------+------------+------+-------------------+----------+---------+-------------------+------+----------+-------------+
2 rows in set, 2 warnings (0.00 sec)
DEPENDENT UNION
в комплектеUNION
илиUNION ALL
В большом запросе , если каждый маленький запрос зависит от внешнего запроса, то, кроме самого левого маленького запроса, остальные маленькие запросыselect_type
ЗначениеDEPENDENT UNION
.
mysql> EXPLAIN SELECT * FROM s1 WHERE key1 IN (SELECT key1 FROM s2 WHERE key1 = 'a' UNION SELECT key1 FROM s1 WHERE key1 = 'b');
+----+--------------------+------------+------------+------+---------------+----------+---------+-------+------+----------+--------------------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+--------------------+------------+------------+------+---------------+----------+---------+-------+------+----------+--------------------------+
| 1 | PRIMARY | s1 | NULL | ALL | NULL | NULL | NULL | NULL | 9688 | 100.00 | Using where |
| 2 | DEPENDENT SUBQUERY | s2 | NULL | ref | idx_key1 | idx_key1 | 303 | const | 12 | 100.00 | Using where; Using index |
| 3 | DEPENDENT UNION | s1 | NULL | ref | idx_key1 | idx_key1 | 303 | const | 8 | 100.00 | Using where; Using index |
| NULL | UNION RESULT | <union2,3> | NULL | ALL | NULL | NULL | NULL | NULL | NULL | NULL | Using temporary |
+----+--------------------+------------+------------+------+---------------+----------+---------+-------+------+----------+--------------------------+
4 rows in set, 1 warning (0.03 sec)
DERIVED
Для запроса, содержащего производную таблицу, выполненного материализованным образом, подзапрос, соответствующий производной таблицеselect_type
этоDERIVED
, например, следующий запрос:
mysql> EXPLAIN SELECT * FROM (SELECT key1, count(*) as c FROM s1 GROUP BY key1) AS derived_s1 where c > 1;
+----+-------------+------------+------------+-------+---------------+----------+---------+------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+------------+------------+-------+---------------+----------+---------+------+------+----------+-------------+
| 1 | PRIMARY | <derived2> | NULL | ALL | NULL | NULL | NULL | NULL | 9688 | 33.33 | Using where |
| 2 | DERIVED | s1 | NULL | index | idx_key1 | idx_key1 | 303 | NULL | 9688 | 100.00 | Using index |
+----+-------------+------------+------------+-------+---------------+----------+---------+------+------+----------+-------------+
2 rows in set, 1 warning (0.00 sec)
MATERIALIZED
Когда оптимизатор запросов выполняет инструкцию, содержащую подзапрос, и выбирает материализацию подзапроса для выполнения запроса на соединение с внешним запросом, соответствующий подзапросselect_type
собственностьMATERIALIZED
, например следующий запрос:
mysql> EXPLAIN SELECT * FROM s1 WHERE key1 IN (SELECT key1 FROM s2);
+----+--------------+-------------+------------+--------+---------------+------------+---------+-------------------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+--------------+-------------+------------+--------+---------------+------------+---------+-------------------+------+----------+-------------+
| 1 | SIMPLE | s1 | NULL | ALL | idx_key1 | NULL | NULL | NULL | 9688 | 100.00 | Using where |
| 1 | SIMPLE | <subquery2> | NULL | eq_ref | <auto_key> | <auto_key> | 303 | xiaohaizi.s1.key1 | 1 | 100.00 | NULL |
| 2 | MATERIALIZED | s2 | NULL | index | idx_key1 | idx_key1 | 303 | NULL | 9954 | 100.00 | Using index |
+----+--------------+-------------+------------+--------+---------------+------------+---------+-------------------+------+----------+-------------+
3 rows in set, 1 warning (0.01 sec)
type
Как указано выше,Запись плана выполнения представляет собой метод доступа к таблице.,один из нихtype
Столбцы используются для описания методов доступа. Полный метод доступа выглядит следующим образом:system
,const
,eq_ref
,ref
,fulltext
,ref_or_null
,index_merge
,unique_subquery
,index_subquery
,range
,index
,ALL
.
system
Когда в таблице есть только одна запись и статистика механизма хранения, используемого таблицей, точна, напримерMyISAM
,Memory
, то метод доступа к таблице такойsystem
.
const
Когда эквивалентное сопоставление выполняется на основе первичного ключа или уникального столбца вторичного индекса и константы, метод доступа к одной таблицеconst
.
mysql> EXPLAIN SELECT * FROM s1 WHERE id = 5;
+----+-------------+-------+------------+-------+---------------+---------+---------+-------+------+----------+-------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+-------+---------------+---------+---------+-------+------+----------+-------+
| 1 | SIMPLE | s1 | NULL | const | PRIMARY | PRIMARY | 4 | const | 1 | 100.00 | NULL |
+----+-------------+-------+------------+-------+---------------+---------+---------+-------+------+----------+-------+
1 row in set, 1 warning (0.01 sec)
eq_ref
В запросе на соединение, если доступ к управляемой таблице осуществляется посредством сопоставления эквивалентных значений первичного ключа или уникального столбца вторичного индекса (если первичный ключ или уникальный вторичный индекс является совместным индексом, все столбцы индекса должны быть сопоставлены с уравновешенным значением), метод доступа к управляемой таблицеeq_ref
.
mysql> EXPLAIN SELECT * FROM s1 INNER JOIN s2 ON s1.id = s2.id;
+----+-------------+-------+------------+--------+---------------+---------+---------+-----------------+------+----------+-------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+--------+---------------+---------+---------+-----------------+------+----------+-------+
| 1 | SIMPLE | s1 | NULL | ALL | PRIMARY | NULL | NULL | NULL | 9688 | 100.00 | NULL |
| 1 | SIMPLE | s2 | NULL | eq_ref | PRIMARY | PRIMARY | 4 | xiaohaizi.s1.id | 1 | 100.00 | NULL |
+----+-------------+-------+------------+--------+---------------+---------+---------+-----------------+------+----------+-------+
2 rows in set, 1 warning (0.01 sec)
ref
Когда таблица запрашивается посредством совпадения значений между общим столбцом вторичного индекса и константой, метод доступа к таблице может бытьref
.
mysql> EXPLAIN SELECT * FROM s1 WHERE key1 = 'a';
+----+-------------+-------+------------+------+---------------+----------+---------+-------+------+----------+-------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+------+---------------+----------+---------+-------+------+----------+-------+
| 1 | SIMPLE | s1 | NULL | ref | idx_key1 | idx_key1 | 303 | const | 8 | 100.00 | NULL |
+----+-------------+-------+------------+------+---------------+----------+---------+-------+------+----------+-------+
1 row in set, 1 warning (0.04 sec)
ref_or_null
При выполнении запроса на сопоставление равных значений для общего вторичного индекса значение столбца индекса также может бытьNULL
значение, то метод доступа к таблице может бытьref_or_null
.
mysql> EXPLAIN SELECT * FROM s1 WHERE key1 = 'a' OR key1 IS NULL;
+----+-------------+-------+------------+-------------+---------------+----------+---------+-------+------+----------+-----------------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+-------------+---------------+----------+---------+-------+------+----------+-----------------------+
| 1 | SIMPLE | s1 | NULL | ref_or_null | idx_key1 | idx_key1 | 303 | const | 9 | 100.00 | Using index condition |
+----+-------------+-------+------------+-------------+---------------+----------+---------+-------+------+----------+-----------------------+
1 row in set, 1 warning (0.01 sec)
index_merge
Как правило, для запроса к таблице можно использовать только один индекс, но в некоторых сценариях также можно использовать слияние индексов.type
этоindex_merge
.
mysql> EXPLAIN SELECT * FROM s1 WHERE key1 = 'a' OR key3 = 'a';
+----+-------------+-------+------------+-------------+-------------------+-------------------+---------+------+------+----------+---------------------------------------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+-------------+-------------------+-------------------+---------+------+------+----------+---------------------------------------------+
| 1 | SIMPLE | s1 | NULL | index_merge | idx_key1,idx_key3 | idx_key1,idx_key3 | 303,303 | NULL | 14 | 100.00 | Using union(idx_key1,idx_key3); Using where |
+----+-------------+-------+------------+-------------+-------------------+-------------------+---------+------+------+----------+---------------------------------------------+
1 row in set, 1 warning (0.01 sec)
слияние индексов
Как правило, для выполнения запроса будет использоваться не более одного индекса. Однако в особых случаях может также использоваться несколько вторичных индексов, и запросы, выполняемые таким образом, называютсяindex_merge
. Ниже приведены три конкретных алгоритма слияния индексов.
-
Объединение перекрестков
Intersection
Переводится как перекресток. Это означает, что запрос может использовать несколько вторичных индексов, и результаты, полученные из нескольких вторичных индексов, будут пересекаться. Например, следующий запрос:SELECT * FROM single_table WHERE key1 = 'a' AND key3 = 'b';
-
Союз слияния Когда мы пишем операторы запроса, мы часто хотим удалить записи, которые соответствуют определенному условию поиска, а также удалить записи, которые соответствуют другому условию поиска.Мы говорим, что между этими различными условиями поиска существует отношение ИЛИ. Например:
SELECT * FROM single_table WHERE key1 = 'a' OR key3 = 'b'
Intersection
Это значение пересечения, которое подходит для использования между критериями поиска, использующими разные индексы.AND
подключенное состояние;Union
это значение объединения, которое подходит для использования между условиями поиска с использованием разных индексовOR
связанная ситуация. -
Слияние сортировки-объединения
Union
Условия использования слияния индексов слишком жесткие. Необходимо обеспечить, чтобы каждый столбец вторичного индекса мог использоваться при условии совпадения значений. Например, нельзя использовать следующий запрос.Union
Объединение индексов:SELECT * FROM single_table WHERE key1 < 'a' OR key3 > 'z'
Мы сортируем приведенное выше сначала по значению первичного ключа записи вторичного индекса, а затем по
Union
Способ выполнения режима слияния индексов называетсяSort-Union
Слияние индексов, очевидно, этоSort-Union
Объединение индексов более эффективно, чем простоеUnion
Слияние индексов добавляет еще один шаг к сортировке значений первичного ключа записей вторичного индекса.
unique_subquery
Подобно управляемой таблице в соединении двух таблицeq_ref
метод доступа,unique_subquery
нацелен на некоторые содержащиеIN
В операторе запроса подзапроса, если оптимизатор запросов решитIN
Подзапрос преобразуется вEXISTS
подзапрос, а подзапрос может использовать первичный ключ для совпадения значений, то план выполнения подзапросаtype
Значение столбцаunique_subquery
, например следующий запрос:
mysql> EXPLAIN SELECT * FROM s1 WHERE key2 IN (SELECT id FROM s2 where s1.key1 = s2.key1) OR key3 = 'a';
+----+--------------------+-------+------------+-----------------+------------------+---------+---------+------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+--------------------+-------+------------+-----------------+------------------+---------+---------+------+------+----------+-------------+
| 1 | PRIMARY | s1 | NULL | ALL | idx_key3 | NULL | NULL | NULL | 9688 | 100.00 | Using where |
| 2 | DEPENDENT SUBQUERY | s2 | NULL | unique_subquery | PRIMARY,idx_key1 | PRIMARY | 4 | func | 1 | 10.00 | Using where |
+----+--------------------+-------+------------+-----------------+------------------+---------+---------+------+------+----------+-------------+
2 rows in set, 2 warnings (0.00 sec)
index_subquery
index_subquery
иunique_subquery
Аналогично, за исключением того, что для доступа к таблицам в подзапросах используются обычные индексы, например:
mysql> EXPLAIN SELECT * FROM s1 WHERE common_field IN (SELECT key3 FROM s2 where s1.key1 = s2.key1) OR key3 = 'a';
+----+--------------------+-------+------------+----------------+-------------------+----------+---------+------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+--------------------+-------+------------+----------------+-------------------+----------+---------+------+------+----------+-------------+
| 1 | PRIMARY | s1 | NULL | ALL | idx_key3 | NULL | NULL | NULL | 9688 | 100.00 | Using where |
| 2 | DEPENDENT SUBQUERY | s2 | NULL | index_subquery | idx_key1,idx_key3 | idx_key3 | 303 | func | 1 | 10.00 | Using where |
+----+--------------------+-------+------------+----------------+-------------------+----------+---------+------+------+----------+-------------+
2 rows in set, 2 warnings (0.01 sec)
range
Если вы используете индекс для получения записей некоторого интервала диапазона, вы можете использоватьrange
Методы доступа, такие как этот запрос ниже:
mysql> EXPLAIN SELECT * FROM s1 WHERE key1 IN ('a', 'b', 'c');
+----+-------------+-------+------------+-------+---------------+----------+---------+------+------+----------+-----------------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+-------+---------------+----------+---------+------+------+----------+-----------------------+
| 1 | SIMPLE | s1 | NULL | range | idx_key1 | idx_key1 | 303 | NULL | 27 | 100.00 | Using index condition |
+----+-------------+-------+------------+-------+---------------+----------+---------+------+------+----------+-----------------------+
1 row in set, 1 warning (0.01 sec)
index
Когда необходимо просмотреть все записи индекса, метод доступа к таблицеindex
.
mysql> EXPLAIN SELECT key_part2 FROM s1 WHERE key_part3 = 'a';
+----+-------------+-------+------------+-------+---------------+--------------+---------+------+------+----------+--------------------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+-------+---------------+--------------+---------+------+------+----------+--------------------------+
| 1 | SIMPLE | s1 | NULL | index | NULL | idx_key_part | 909 | NULL | 9688 | 10.00 | Using where; Using index |
+----+-------------+-------+------------+-------+---------------+--------------+---------+------+------+----------+--------------------------+
1 row in set, 1 warning (0.00 sec)
ALL
полное сканирование таблицы
возможные_ключи и ключи
possible_keys
Столбец указывает, какие индексы могут использоваться при выполнении однотабличного запроса к таблице в операторе запроса.key
Столбец указывает, какие индексы на самом деле используются, например, следующий запрос:
mysql> EXPLAIN SELECT * FROM s1 WHERE key1 > 'z' AND key3 = 'a';
+----+-------------+-------+------------+------+-------------------+----------+---------+-------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+------+-------------------+----------+---------+-------+------+----------+-------------+
| 1 | SIMPLE | s1 | NULL | ref | idx_key1,idx_key3 | idx_key3 | 303 | const | 6 | 2.75 | Using where |
+----+-------------+-------+------------+------+-------------------+----------+---------+-------+------+----------+-------------+
1 row in set, 1 warning (0.01 sec)
key_len
key_len
Столбец представляет собой максимальную длину записи индекса, когда оптимизатор решает использовать индекс для выполнения запроса. Он состоит из следующих трех частей:
- Для столбца индекса, использующего тип фиксированной длины, максимальная длина занимаемой им дисковой памяти является фиксированным значением; для столбца индекса, указанный набор символов которого является типом переменной длины, например, тип столбца индекса является
VARCHAR(100)
, используется набор символовutf8
, то максимальный объем памяти, фактически занимаемый столбцом, равен100 × 3 = 300
байт. - Если столбец индекса может хранить
NULL
Ценность,key_len
чем нельзя хранитьNULL
Еще 1 байт для значения. - Для полей переменной длины будет 2 байта пространства для хранения фактической длины столбца переменной длины.
ref
Когда запрос выполняется с использованием условий, соответствующих значениям столбцов индекса, то есть когда метод доступаconst
,eq_ref
,ref
,ref_or_null
,unique_subquery
,index_subquery
один из них,ref
Столбец показывает конкретную информацию, которая эквивалентна столбцу индекса, например, просто константу или определенный столбец. Взгляните на запрос ниже:
mysql> EXPLAIN SELECT * FROM s1 WHERE key1 = 'a';
+----+-------------+-------+------------+------+---------------+----------+---------+-------+------+----------+-------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+------+---------------+----------+---------+-------+------+----------+-------+
| 1 | SIMPLE | s1 | NULL | ref | idx_key1 | idx_key1 | 303 | const | 8 | 100.00 | NULL |
+----+-------------+-------+------------+------+---------------+----------+---------+-------+------+----------+-------+
1 row in set, 1 warning (0.01 sec)
rows
Если оптимизатор запросов решает использовать полное сканирование таблицы для выполнения запроса к таблице,rows
Столбец представляет количество строк, которые, как ожидается, будут просканированы.Если для выполнения запроса используется индекс, план выполненияrows
Столбец представляет ожидаемое количество строк записи индекса, которые должны быть просмотрены. Например, следующий запрос:
mysql> EXPLAIN SELECT * FROM s1 WHERE key1 > 'z';
+----+-------------+-------+------------+-------+---------------+----------+---------+------+------+----------+-----------------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+-------+---------------+----------+---------+------+------+----------+-----------------------+
| 1 | SIMPLE | s1 | NULL | range | idx_key1 | idx_key1 | 303 | NULL | 266 | 100.00 | Using index condition |
+----+-------------+-------+------------+-------+---------------+----------+---------+------+------+----------+-----------------------+
1 row in set, 1 warning (0.00 sec)
filtered
Мы уделяем больше внимания записям плана выполнения, соответствующим ведущей таблице в запросе на соединение.filtered
значение, так как это напрямую влияет на значение разветвления таблицы дисков. существуетrows
При таких обстоятельствах,filtered
Чем больше значение, тем меньше значение разветвления и, возможно, выше эффективность. Например:
mysql> EXPLAIN SELECT * FROM s1 INNER JOIN s2 ON s1.key1 = s2.key1 WHERE s1.common_field = 'a';
+----+-------------+-------+------------+------+---------------+----------+---------+-------------------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+------+---------------+----------+---------+-------------------+------+----------+-------------+
| 1 | SIMPLE | s1 | NULL | ALL | idx_key1 | NULL | NULL | NULL | 9688 | 10.00 | Using where |
| 1 | SIMPLE | s2 | NULL | ref | idx_key1 | idx_key1 | 303 | xiaohaizi.s1.key1 | 1 | 100.00 | NULL |
+----+-------------+-------+------------+------+---------------+----------+---------+-------------------+------+----------+-------------+
2 rows in set, 1 warning (0.00 sec)
Как видно из плана выполнения, оптимизатор запросов намеренs1
Как водительский стол,s2
как ведомый стол. мы можем видеть таблицу дисковs1
план выполнения таблицыrows
указан как 9688,filtered
Столбец равен 10,00, что означает, что значение разветвления таблицы драйверов s1 равно9688 × 10.00% = 968.8
, значит, примерно968
запрос.
Extra
Extra
Он используется для иллюстрации некоторой информации, чтобы помочь нам более точно понять запрос. Ниже мы выбираем несколько наиболее распространенных из них.
No tables used
Когда оператор запроса не имеетfrom
появляется, когда словоNo tables used
.
Impossible WHERE
когда оператор запросаwhere
слова всегдаfalse
появляется, когдаImpossible WHERE
.
No matching min/max row
Когда список запросовmin()
илиmax()
Агрегатная функция, но она появится, когда соответствующая запись не соответствуетNo matching min/max row
.
Using index
когда используешь索引覆盖
появится, когдаUsing index
.
Using index condition
Если при выполнении запроса используетсяУсловие индекса Pushdown, он появитсяUsing index condition
. Например:
SELECT * FROM s1 WHERE key1 > 'z' AND key1 LIKE '%a';
1. Сначала поkey1 > 'z'
Это условие находит вторичный индексidx_key1
Соответствующие записи вторичного индекса.
2, не возвращать таблицу, но тест выполненkey1 LIKE '%a'
условие и, наконец, запишите вторичный индекс, который соответствует условию, обратно в таблицу.
Using where
При выполнении запроса с использованием полного сканирования таблицы, если оператор запроса содержитwhere
состояние, будетUsing where
.
При выполнении запроса с использованием индексированного доступа, еслиwhere
предложение содержит неиндексированные поля столбца, также отображаетсяUsing where
.
Using join buffer (Block Nested Loop)
Во время выполнения запроса на соединение, когда управляемая таблица не может эффективно использовать индекс для увеличения скорости доступа,MySQL
Как правило, блок с именемjoin buffer
блоков памяти для ускорения запросов, что мы называемАлгоритм вложенного цикла на основе блоков, например следующий запрос:
mysql> EXPLAIN SELECT * FROM s1 INNER JOIN s2 ON s1.common_field = s2.common_field;
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+----------------------------------------------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+----------------------------------------------------+
| 1 | SIMPLE | s1 | NULL | ALL | NULL | NULL | NULL | NULL | 9688 | 100.00 | NULL |
| 1 | SIMPLE | s2 | NULL | ALL | NULL | NULL | NULL | NULL | 9954 | 10.00 | Using where; Using join buffer (Block Nested Loop) |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+----------------------------------------------------+
2 rows in set, 1 warning (0.03 sec)
Not exists
Когда мы используем левое (внешнее) соединение, еслиWHERE
предложение содержит требование, чтобы столбец управляемой таблицы был равенNULL
значение критерия поиска, и этот столбец не может хранитьNULL
значение, то в плане выполнения таблицыExtra
колонка подскажетNot exists
Дополнительная информация, например:
mysql> EXPLAIN SELECT * FROM s1 LEFT JOIN s2 ON s1.key1 = s2.key1 WHERE s2.id IS NULL;
+----+-------------+-------+------------+------+---------------+----------+---------+-------------------+------+----------+-------------------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+------+---------------+----------+---------+-------------------+------+----------+-------------------------+
| 1 | SIMPLE | s1 | NULL | ALL | NULL | NULL | NULL | NULL | 9688 | 100.00 | NULL |
| 1 | SIMPLE | s2 | NULL | ref | idx_key1 | idx_key1 | 303 | xiaohaizi.s1.key1 | 1 | 10.00 | Using where; Not exists |
+----+-------------+-------+------------+-
Использование intersect(...), использование union(...) и использование sort_union(...)
если используетсяслияние индексовВыполните запрос, он появитсяUsing intersect(...)
илиUsing union(...)
илиUsing sort_union(...)
.
Например:
mysql> EXPLAIN SELECT * FROM s1 WHERE key1 = 'a' AND key3 = 'a';
+----+-------------+-------+------------+-------------+-------------------+-------------------+---------+------+------+----------+-------------------------------------------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+-------------+-------------------+-------------------+---------+------+------+----------+-------------------------------------------------+
| 1 | SIMPLE | s1 | NULL | index_merge | idx_key1,idx_key3 | idx_key3,idx_key1 | 303,303 | NULL | 1 | 100.00 | Using intersect(idx_key3,idx_key1); Using where |
+----+-------------+-------+------------+-------------+-------------------+-------------------+---------+------+------+----------+-------------------------------------------------+
1 row in set, 1 warning (0.01 sec)
Zero limit
когдаlimit
Когда параметр предложения равен 0, он появитсяZero limit
.
Using filesort
В некоторых случаях индекс можно использовать для сортировки записей в результирующем наборе, например следующий запрос:
mysql> EXPLAIN SELECT * FROM s1 ORDER BY key1 LIMIT 10;
+----+-------------+-------+------------+-------+---------------+----------+---------+------+------+----------+-------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+-------+---------------+----------+---------+------+------+----------+-------+
| 1 | SIMPLE | s1 | NULL | index | NULL | idx_key1 | 303 | NULL | 10 | 100.00 | NULL |
+----+-------------+-------+------------+-------+---------------+----------+---------+------+------+----------+-------+
1 row in set, 1 warning (0.03 sec)
Но в большинстве случаев операция сортировки не может использовать индекс, а может использовать только файловую сортировку (filesort
). Если используется сортировкаfilesort
, затем вExtra
столбец появитсяUsing filesort
.
Using temporary
При выполнении многих запросовMySQL
Некоторые функции могут быть выполнены с помощью временных таблиц, такие как дедупликация, сортировка и т. д. Например, мы выполняем множество операций, которые включают в себяDISTINCT
,GROUP BY
,UNION
В процессе запроса других предложений, если индекс не может быть эффективно использован для выполнения запроса,MySQL
Вполне возможно добиваться выполнения запросов путем создания внутренних временных таблиц. Если запрос использует внутреннюю временную таблицу, в плане выполненияExtra
столбец покажетUsing temporary
Подскажите, скажите так:
mysql> EXPLAIN SELECT DISTINCT common_field FROM s1;
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-----------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-----------------+
| 1 | SIMPLE | s1 | NULL | ALL | NULL | NULL | NULL | NULL | 9688 | 100.00 | Using temporary |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-----------------+
1 row in set, 1 warning (0.00 sec)
появляется в плане выполненияUsing temporary
Это плохой знак, потому что создание и обслуживание временных таблиц стоит дорого, поэтому лучше использовать индексы, а не временные таблицы.
Start temporary, End temporary
Оптимизатор запросов сначала попытается преобразовать подзапросы IN вsemi-join
,иsemi-join
Существует много видов стратегий исполнения, когда стратегия исполненияDuplicateWeedout
Когда операция дедупликации выполняется для записей во внешнем запросе путем создания временной таблицы, запускается план выполнения запроса таблицы.Extra
столбец покажетStart temporary
Быстрый, управляемый план выполнения запроса к таблицеExtra
столбец покажетEnd temporary
Подскажите, это:
mysql> EXPLAIN SELECT * FROM s1 WHERE key1 IN (SELECT key3 FROM s2 WHERE common_field = 'a');
+----+-------------+-------+------------+------+---------------+----------+---------+-------------------+------+----------+------------------------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+------+---------------+----------+---------+-------------------+------+----------+------------------------------+
| 1 | SIMPLE | s2 | NULL | ALL | idx_key3 | NULL | NULL | NULL | 9954 | 10.00 | Using where; Start temporary |
| 1 | SIMPLE | s1 | NULL | ref | idx_key1 | idx_key1 | 303 | xiaohaizi.s2.key3 | 1 | 100.00 | End temporary |
+----+-------------+-------+------------+------+---------------+----------+---------+-------------------+------+----------+------------------------------+
2 rows in set, 1 warning (0.00 sec)
LooseScan
При преобразовании подзапроса In вsemi-join
, если использоватьLooseScan
Стратегия выполнения в плане выполнения таблицы драйверовExtra
столбец должен показатьLooseScan
Советы, такие как это:
mysql> EXPLAIN SELECT * FROM s1 WHERE key3 IN (SELECT key1 FROM s2 WHERE key1 > 'z');
+----+-------------+-------+------------+-------+---------------+----------+---------+-------------------+------+----------+-------------------------------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+-------+---------------+----------+---------+-------------------+------+----------+-------------------------------------+
| 1 | SIMPLE | s2 | NULL | range | idx_key1 | idx_key1 | 303 | NULL | 270 | 100.00 | Using where; Using index; LooseScan |
| 1 | SIMPLE | s1 | NULL | ref | idx_key3 | idx_key3 | 303 | xiaohaizi.s2.key1 | 1 | 100.00 | NULL |
+----+-------------+-------+------------+-------+---------------+----------+---------+-------------------+------+----------+-------------------------------------+
2 rows in set, 1 warning (0.01 sec)
FirstMatch(tbl_name)
При преобразовании подзапроса In вsemi-join
, если использоватьFirstMatch
Стратегия выполнения, затем в плане выполнения управляемой таблицыExtra
столбец должен показатьFirstMatch(tbl_name)
Советы, такие как это:
mysql> EXPLAIN SELECT * FROM s1 WHERE common_field IN (SELECT key1 FROM s2 where s1.key3 = s2.key3);
+----+-------------+-------+------------+------+-------------------+----------+---------+-------------------+------+----------+-----------------------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+------+-------------------+----------+---------+-------------------+------+----------+-----------------------------+
| 1 | SIMPLE | s1 | NULL | ALL | idx_key3 | NULL | NULL | NULL | 9688 | 100.00 | Using where |
| 1 | SIMPLE | s2 | NULL | ref | idx_key1,idx_key3 | idx_key3 | 303 | xiaohaizi.s1.key3 | 1 | 4.87 | Using where; FirstMatch(s1) |
+----+-------------+-------+------------+------+-------------------+----------+---------+-------------------+------+----------+-----------------------------+
2 rows in set, 2 warnings (0.00 sec)
Нелегко быть оригинальным. Если вы считаете, что статья написана хорошо, пожалуйста, поставьте лайк 👍 и поддержите ее~
Добро пожаловать в мой проект с открытым исходным кодом:Облегченная среда вызовов HTTP для SpringBoot