Объясните подробно план выполнения mysql, больше не нужно бояться оптимизации sql!

база данных

Всем известно, что 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Если запрос выполняется как управляющая таблица, то процесс выполнения выглядит следующим образом:looseScanКак показано на рисунке, в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-joinsemi-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