10.9.3 Подсказки оптимизатору
Один из способов управления стратегиями оптимизатора — это установка системной переменной optimizer_switch (см. Раздел 10.9.2, «Переключаемые оптимизации»). Изменения в этой переменной влияют на выполнение всех последующих запросов; для того, чтобы повлиять на один запрос иначе, чем на другой, необходимо изменить optimizer_switch перед каждым запросом.
Другой способ управления оптимизатором — использование подсказок оптимизатора, которые можно указать в отдельных операторах. Поскольку подсказки оптимизатора применяются на основе каждого оператора, они обеспечивают более точный контроль планов выполнения операторов, чем можно достичь с помощью optimizer_switch. Например, вы можете включить оптимизацию для одной таблицы в операторе и отключить оптимизацию для другой таблицы. Подсказки внутри оператора имеют приоритет над optimizer_switch флагами.
Примеры:
SELECT /*+ NO_RANGE_OPTIMIZATION(t3 PRIMARY, f2_idx) */ f1
FROM t3 WHERE f1 > 30 AND f1 < 33;
SELECT /*+ BKA(t1) NO_BKA(t2) */ * FROM t1 INNER JOIN t2 WHERE ...;
SELECT /*+ NO_ICP(t1, t2) */ * FROM t1 INNER JOIN t2 WHERE ...;
SELECT /*+ SEMIJOIN(FIRSTMATCH, LOOSESCAN) */ * FROM t1 ...;
EXPLAIN SELECT /*+ NO_ICP(t1) */ * FROM t1 WHERE ...;
SELECT /*+ MERGE(dt) */ * FROM (SELECT * FROM t1) AS dt;
INSERT /*+ SET_VAR(foreign_key_checks=OFF) */ INTO t2 VALUES(2);
Подсказки оптимизатора, описанные здесь, отличаются от подсказок индексов, описанных в Разделе 10.9.4, «Подсказки индексов». Подсказки оптимизатора и индексов могут использоваться по отдельности или вместе.
Обзор подсказок оптимизатору
Подсказки оптимизатору применяются на разных уровнях области:
Глобальный: подсказка влияет на все утверждение
Блок запроса: подсказка влияет на конкретный блок запроса в утверждении
Уровень таблицы: подсказка влияет на конкретную таблицу в блоке запроса
Уровень индекса: подсказка влияет на конкретный индекс в таблице
В следующей таблице обобщены доступные подсказки оптимизатору, стратегии оптимизатора, на которые они влияют, и области или области, в которых они применяются. Более подробная информация представлена ниже.
Таблица 10.2 Доступные подсказки оптимизатору
| Имя подсказки | Описание | Применимые области |
|---|---|---|
BKA, NO_BKA
| Влияет на обработку объединения Batched Key Access | Блок запроса, таблица |
BNL, NO_BNL
| Влияет на оптимизацию объединения hash join | Блок запроса, таблица |
DERIVED_CONDITION_PUSHDOWN, NO_DERIVED_CONDITION_PUSHDOWN
| Использовать или игнорировать оптимизацию перемещения производного условия для материализованных производных таблиц | Блок запроса, таблица |
GROUP_INDEX, NO_GROUP_INDEX
| Использовать или игнорировать указанный индекс или индексы для сканирования индексов в операциях GROUP BY | Индекс |
HASH_JOIN, NO_HASH_JOIN
| Влияет на оптимизацию Hash Join (без эффекта в MySQL 9.2) | Блок запроса, таблица |
INDEX, NO_INDEX
| Действует как комбинация JOIN_INDEX, GROUP_INDEX и ORDER_INDEX, или как комбинация NO_JOIN_INDEX, NO_GROUP_INDEX и NO_ORDER_INDEX | Индекс |
INDEX_MERGE, NO_INDEX_MERGE
| Влияет на оптимизацию Index Merge | Таблица, индекс |
JOIN_FIXED_ORDER | Использовать порядок таблиц, указанный в FROM-оператор, для порядка объединения | Блок запроса |
JOIN_INDEX, NO_JOIN_INDEX
| Использовать или игнорировать указанный индекс или индексы для любого метода доступа | Индекс |
JOIN_ORDER | Использовать порядок таблиц, указанный в подсказке, для порядка объединения | Блок запроса |
JOIN_PREFIX | Использовать порядок таблиц, указанный в подсказке, для первых таблиц в порядке объединения | Блок запроса |
JOIN_SUFFIX | Использовать порядок таблиц, указанный в подсказке, для последних таблиц в порядке объединения | Блок запроса |
MAX_EXECUTION_TIME | Ограничение времени выполнения утверждения | Глобальный |
MERGE, NO_MERGE
| Влияет на слияние производной таблицы/представления в внешний блок запроса | Таблица |
MRR, NO_MRR
| Влияет на оптимизацию Multi-Range Read | Таблица, индекс |
NO_ICP | Влияет на оптимизацию Index Condition Pushdown | Таблица, индекс |
NO_RANGE_OPTIMIZATION | Влияет на оптимизацию диапазонов | Таблица, индекс |
ORDER_INDEX, NO_ORDER_INDEX
| Использовать или игнорировать указанный индекс или индексы для сортировки строк | Индекс |
QB_NAME | Присваивает имя блоку запроса | Блок запроса |
RESOURCE_GROUP | Установить группу ресурсов во время выполнения утверждения | Глобальный |
SEMIJOIN, NO_SEMIJOIN
| Влияет на стратегии semijoin и antijoin | Блок запроса |
SKIP_SCAN, NO_SKIP_SCAN
| Влияет на оптимизацию Skip Scan | Таблица, индекс |
SET_VAR | Установка переменной во время выполнения утверждения | Глобальный |
SUBQUERY | Влияет на материализацию, IN-на-EXISTS стратегии подзапросов | Блок запроса |
Отключение оптимизации предотвращает ее использование оптимизатором. Включение оптимизации означает, что оптимизатор свободен использовать стратегию, если она применима к выполнению утверждения, а не то, что оптимизатор обязательно ее использует.
Синтаксис подсказок оптимизатора
MySQL поддерживает комментарии в операторах SQL, как описано в разделе 11.7, «Комментарии». Подсказки оптимизатора должны быть указаны внутри /*+ ... */ комментариев. То есть, подсказки оптимизатора используют вариант синтаксиса комментариев /* ... */ C-стиля с + символом, следующим за /* последовательностью открывающего комментария. Примеры:
/*+ BKA(t1) */
/*+ BNL(t1, t2) */
/*+ NO_RANGE_OPTIMIZATION(t4 PRIMARY) */
/*+ QB_NAME(qb2) */
Разрешается использование пробелов после + символа.
Парсер распознаёт комментарии с подсказками оптимизатора после начального ключевого слова операторов SELECT, UPDATE, INSERT, REPLACE и DELETE. Подсказки разрешены в следующих контекстах:
-
В начале операторов запросов и изменений данных:
SELECT /*+ ... */ ... INSERT /*+ ... */ ... REPLACE /*+ ... */ ... UPDATE /*+ ... */ ... DELETE /*+ ... */ ...
-
В начале блоков запросов:
(SELECT /*+ ... */ ... ) (SELECT ... ) UNION (SELECT /*+ ... */ ... ) (SELECT /*+ ... */ ... ) UNION (SELECT /*+ ... */ ... ) UPDATE ... WHERE x IN (SELECT /*+ ... */ ...) INSERT ... SELECT /*+ ... */ ...
-
В операторах, допускающих подсказки, перед которыми стоит
EXPLAIN. Например:EXPLAIN SELECT /*+ ... */ ... EXPLAIN UPDATE ... WHERE x IN (SELECT /*+ ... */ ...)
Это означает, что вы можете использовать
EXPLAINдля просмотра того, как подсказки оптимизатора влияют на планы выполнения. ИспользуйтеSHOW WARNINGSсразу послеEXPLAIN, чтобы увидеть, как используются подсказки. РасширенныйEXPLAINвывод, отображаемый последующимSHOW WARNINGS, указывает, какие подсказки были использованы. Игнорируемые подсказки не отображаются.
Комментарий с подсказкой может содержать несколько подсказок, но блок запроса не может содержать несколько комментариев с подсказками. Это верно:
SELECT /*+ BNL(t1) BKA(t2) */ ...
Но это неверно:
SELECT /*+ BNL(t1) */ /* BKA(t2) */ ...
Когда комментарий с подсказкой содержит несколько подсказок, существует возможность дублирования и конфликтов. Применяются следующие общие рекомендации. Для конкретных типов подсказок могут применяться дополнительные правила, как указано в описаниях подсказок.
Дублирующие подсказки: Для подсказки, такой как
/*+ MRR(idx1) MRR(idx1) */, MySQL использует первую подсказку и выводит предупреждение о дублирующей подсказке.Конфликтующие подсказки: Для подсказки, такой как
/*+ MRR(idx1) NO_MRR(idx1) */, MySQL использует первую подсказку и выводит предупреждение о второй конфликтующей подсказке.
Имена блоков запросов являются идентификаторами и следуют обычным правилам относительно того, какие имена допустимы и как их заключать в кавычки (см. раздел 11.2, «Имена объектов схемы»).
Имена подсказок, имена блоков запросов и имена стратегий нечувствительны к регистру. Ссылки на имена таблиц и индексов следуют обычным правилам чувствительности к регистру идентификаторов (см. раздел 11.2.3, «Чувствительность к регистру идентификаторов»).
Указания оптимизатора для порядка соединения
Указания для порядка соединения влияют на порядок, в котором оптимизатор соединяет таблицы.
Синтаксис указания JOIN_FIXED_ORDER:
hint_name([@query_block_name])
Синтаксис других указаний порядка соединения:
hint_name([@query_block_name] tbl_name [, tbl_name] ...)
hint_name(tbl_name[@query_block_name] [, tbl_name[@query_block_name]] ...)
Синтаксис ссылается на следующие термины:
-
hint_name: Разрешены следующие имена указаний:JOIN_FIXED_ORDER: Принуждает оптимизатор соединять таблицы в порядке их появления в предложенииFROM. Это эквивалентно указаниюSELECT STRAIGHT_JOIN.JOIN_ORDER: Указывает оптимизатору порядок соединения таблиц. Указание относится к указанным таблицам. Оптимизатор может поместить таблицы, не указанные в списке, в любой части порядка соединения, в том числе между указанными таблицами.JOIN_PREFIX: Указывает оптимизатору порядок соединения таблиц для первых таблиц в плане выполнения соединения. Указание относится к указанным таблицам. Оптимизатор размещает все другие таблицы после указанных.JOIN_SUFFIX: Указывает оптимизатору порядок соединения таблиц для последних таблиц в плане выполнения соединения. Указание относится к указанным таблицам. Оптимизатор размещает все другие таблицы перед указанными.
-
tbl_name: Имя таблицы, используемой в запросе. Указание, содержащее имена таблиц, относится ко всем указанным таблицам. УказаниеJOIN_FIXED_ORDERне указывает таблицы и относится ко всем таблицам в предложенииFROMблока запроса, в котором оно находится.Если у таблицы есть псевдоним, указания должны ссылаться на псевдоним, а не на имя таблицы.
Имена таблиц в указаниях не могут быть квалифицированы именами схем.
query_block_name: Блок запроса, к которому относится указание. Если указание не содержит ведущего@, то указание относится к блоку запроса, в котором оно находится. Для синтаксисаquery_block_nameуказание относится к указанной таблице в указанном блоке запроса. Для присвоения имени блоку запроса см. Указания оптимизатора для именования блоков запросов.tbl_name@query_block_name
Пример:
SELECT
/*+ JOIN_PREFIX(t2, t5@subq2, t4@subq1)
JOIN_ORDER(t4@subq1, t3)
JOIN_SUFFIX(t1) */
COUNT(*) FROM t1 JOIN t2 JOIN t3
WHERE t1.f1 IN (SELECT /*+ QB_NAME(subq1) */ f1 FROM t4)
AND t2.f1 IN (SELECT /*+ QB_NAME(subq2) */ f1 FROM t5);
Указания управляют поведением таблиц полусоединения, которые объединяются с внешним блоком запроса. Если подзапросы subq1 и subq2 преобразуются в полусоединения, таблицы t4@subq1 и t5@subq2 объединяются с внешним блоком запроса. В этом случае указание, заданное во внешнем блоке запроса, управляет поведением таблиц t4@subq1, t5@subq2.
Оптимизатор разрешает указания порядка соединения в соответствии со следующими принципами:
-
Несколько экземпляров указаний
Применяется только одно указание
JOIN_PREFIXиJOIN_SUFFIXкаждого типа. Любые последующие указания того же типа игнорируются с предупреждением.JOIN_ORDERможет быть указано несколько раз.Примеры:
/*+ JOIN_PREFIX(t1) JOIN_PREFIX(t2) */
Второе указание
JOIN_PREFIXигнорируется с предупреждением./*+ JOIN_PREFIX(t1) JOIN_SUFFIX(t2) */
Оба указания применяются. Предупреждение не возникает.
/*+ JOIN_ORDER(t1, t2) JOIN_ORDER(t2, t3) */
Оба указания применяются. Предупреждение не возникает.
-
Противоречивые указания
В некоторых случаях указания могут противоречить друг другу, например, когда
JOIN_ORDERиJOIN_PREFIXимеют порядки таблиц, которые невозможно применить одновременно:SELECT /*+ JOIN_ORDER(t1, t2) JOIN_PREFIX(t2, t1) */ ... FROM t1, t2;
В этом случае применяется первое указание, а последующие противоречивые указания игнорируются без предупреждения. Действительное указание, которое невозможно применить, молча игнорируется без предупреждения.
-
Игнорируемые указания
Указание игнорируется, если таблица, указанная в указании, имеет циклическую зависимость.
Пример:
/*+ JOIN_ORDER(t1, t2) JOIN_PREFIX(t2, t1) */
Указание
JOIN_ORDERустанавливает зависимость таблицыt2от таблицыt1. УказаниеJOIN_PREFIXигнорируется, поскольку таблицаt1не может зависеть от таблицыt2. Игнорируемые указания не отображаются в расширенном выводеEXPLAIN. -
Взаимодействие с таблицами
constОптимизатор MySQL помещает таблицы
constна первое место в порядке соединения, а позицию таблицыconstнельзя изменить с помощью указаний. Ссылки на таблицыconstв указаниях порядка соединения игнорируются, хотя само указание все еще применимо. Например, эти записи эквивалентны:JOIN_ORDER(t1,
const_tbl, t2) JOIN_ORDER(t1, t2)Принятые указания, показанные в расширенном выводе
EXPLAIN, включают таблицыconstтак, как они были указаны. -
Взаимодействие с типами операций соединения
MySQL поддерживает несколько типов соединений:
LEFT,RIGHT,INNER,CROSS,STRAIGHT_JOIN. Указание, противоречащее указанному типу соединения, игнорируется без предупреждения.Пример:
SELECT /*+ JOIN_PREFIX(t1, t2) */FROM t2 LEFT JOIN t1;
Здесь возникает конфликт между требуемым порядком соединения в указании и порядком, необходимым для
LEFT JOIN. Указание игнорируется без предупреждения.
Указания оптимизатора на уровне таблиц
Указания на уровне таблиц влияют на:
Использование алгоритмов обработки соединений «Блочное вложенное соединение» (BNL) и «Обработка по ключу» (BKA) (см. Раздел 10.2.1.12, «Соединения с блочным вложенным циклом и обработкой по ключу»).
То, будут ли производные таблицы, ссылки на представления или общие табличные выражения сливаться в внешний блок запроса или материализоваться с помощью внутренней временной таблицы.
Использование оптимизации «Проталкивание условия производной таблицы». См. Раздел 10.2.2.5, «Оптимизация проталкивания условия производной таблицы».
Эти типы указаний применяются к определённым таблицам или ко всем таблицам в блоке запроса.
Синтаксис указаний на уровне таблиц:
hint_name([@query_block_name] [tbl_name [, tbl_name] ...])
hint_name([tbl_name@query_block_name [, tbl_name@query_block_name] ...])
Синтаксис относится к этим терминам:
-
hint_name: Разрешены следующие имена указаний:BKA,NO_BKA: Включение или выключение обработки по ключу для указанных таблиц.BNL,NO_BNL: Включение и выключение оптимизации соединения по хэш-таблице.DERIVED_CONDITION_PUSHDOWN,NO_DERIVED_CONDITION_PUSHDOWN: Включение или выключение оптимизации «Проталкивание условия производной таблицы» для указанных таблиц. Дополнительную информацию см. в Разделе 10.2.2.5, «Оптимизация проталкивания условия производной таблицы».HASH_JOIN,NO_HASH_JOIN: Эти указания не имеют эффекта в MySQL 9.2; используйтеBNLилиNO_BNLвместо них.-
MERGE,NO_MERGE: Включение слияния для указанных таблиц, ссылок на представления или общих табличных выражений; или отключение слияния и использование материализации вместо него.
ПримечаниеЧтобы использовать указание «Блочное вложенное соединение» или «Обработка по ключу» для включения буферизации соединений для любой внутренней таблицы внешнего соединения, буферизация соединений должна быть включена для всех внутренних таблиц внешнего соединения.
-
tbl_name: Имя таблицы, используемой в операторе. Указание применяется ко всем таблицам, которые оно называет. Если указание не называет таблицы, оно применяется ко всем таблицам блока запроса, в котором оно находится.Если у таблицы есть псевдоним, указания должны ссылаться на псевдоним, а не на имя таблицы.
Имена таблиц в указаниях не могут быть квалифицированы именами схем.
query_block_name: Блок запроса, к которому применяется указание. Если указание не включает ведущее@, указание применяется к блоку запроса, в котором оно находится. Дляquery_block_nameсинтаксиса, указание применяется к указанной таблице в указанном блоке запроса. Чтобы назначить имя блоку запроса, см. Указания оптимизатора для именования блоков запросов.tbl_name@query_block_name
Примеры:
SELECT /*+ NO_BKA(t1, t2) */ t1.* FROM t1 INNER JOIN t2 INNER JOIN t3;
SELECT /*+ NO_BNL() BKA(t1) */ t1.* FROM t1 INNER JOIN t2 INNER JOIN t3;
SELECT /*+ NO_MERGE(dt) */ * FROM (SELECT * FROM t1) AS dt;
Указание на уровне таблицы применяется к таблицам, которые получают записи из предыдущих таблиц, а не к отправительским таблицам. Рассмотрим этот оператор:
SELECT /*+ BNL(t2) */ FROM t1, t2;
Если оптимизатор выберет обработку t1 в первую очередь, он применит соединение «Блочное вложенное соединение» к t2, буферизуя строки из t1 перед началом чтения из t2. Если оптимизатор выберет обработку t2 в первую очередь, указание не имеет эффекта, потому что t2 является отправительской таблицей.
Для указаний MERGE и NO_MERGE применяются следующие правила приоритета:
Указание имеет приоритет над любым эвристическим правилом оптимизатора, которое не является техническим ограничением. (Если предоставленное указание как предложение не имеет эффекта, у оптимизатора есть причина игнорировать его.)
Указание имеет приоритет над флагом
derived_mergeпеременной системыoptimizer_switch.Для ссылок на представления, предложение
ALGORITHM={MERGE|TEMPTABLE}в определении представления имеет приоритет над указанием, указанным в запросе, ссылающемся на представление.
Указатели оптимизатора на уровне индексов
Указатели оптимизатора на уровне индексов влияют на стратегии обработки индексов, используемые оптимизатором для конкретных таблиц или индексов. Эти типы указателей влияют на использование функции «Проталкивание условия индекса (ICP)», «Многодиапазонное чтение (MRR)», «Объединение индексов» и оптимизацию диапазонов (см. Раздел 10.2.1, «Оптимизация операторов SELECT»).
Синтаксис указателей на уровне индексов:
hint_name([@query_block_name] tbl_name [index_name [, index_name] ...])
hint_name(tbl_name@query_block_name [index_name [, index_name] ...])
Синтаксис относится к этим терминам:
-
hint_name: Разрешены следующие имена указателей:GROUP_INDEX,NO_GROUP_INDEX: Включают или выключают указанный индекс или индексы для сканирования индексов дляGROUP BYопераций. Эквивалентно указателям индексовFORCE INDEX FOR GROUP BY,IGNORE INDEX FOR GROUP BY.INDEX,NO_INDEX: Действует как комбинацияJOIN_INDEX,GROUP_INDEXиORDER_INDEX, принудительно заставляя сервер использовать указанный индекс или индексы для всех областей применения, или как комбинацияNO_JOIN_INDEX,NO_GROUP_INDEXиNO_ORDER_INDEX, что заставляет сервер игнорировать указанный индекс или индексы для всех областей применения. ЭквивалентноFORCE INDEX,IGNORE INDEX.-
INDEX_MERGE,NO_INDEX_MERGE: Включают или выключают метод доступа «Объединение индексов» для указанной таблицы или индексов. Дополнительную информацию об этом методе доступа см. в Разделе 10.2.1.3, «Оптимизация объединения индексов». Эти указатели применяются ко всем трём алгоритмам объединения индексов.Указатель
INDEX_MERGEзаставляет оптимизатор использовать объединение индексов для указанной таблицы с использованием указанного набора индексов. Если индекс не указан, оптимизатор рассматривает все возможные комбинации индексов и выбирает наименее затратный вариант. Указатель может быть проигнорирован, если комбинация индексов неприменима к данному оператору.Указатель
NO_INDEX_MERGEотключает комбинации объединения индексов, в которые вовлечены любые из указанных индексов. Если указатель не указывает индексы, объединение индексов не допускается для таблицы. JOIN_INDEX,NO_JOIN_INDEX: Заставляет MySQL использовать или игнорировать указанный индекс или индексы для любого метода доступа, такого какref,range,index_mergeи так далее. ЭквивалентноFORCE INDEX FOR JOIN,IGNORE INDEX FOR JOIN.MRR,NO_MRR: Включают или выключают MRR для указанной таблицы или индексов. Указатели MRR применяются только кInnoDBиMyISAMтаблицам. Дополнительную информацию об этом методе доступа см. в Разделе 10.2.1.11, «Оптимизация многодиапазонного чтения».NO_ICP: Отключает ICP для указанной таблицы или индексов. По умолчанию ICP — это кандидатская стратегия оптимизации, поэтому указателя для её включения нет. Дополнительную информацию об этом методе доступа см. в Разделе 10.2.1.6, «Оптимизация проталкивания условия индекса».-
NO_RANGE_OPTIMIZATION: Отключает доступ к индексу по диапазонам для указанной таблицы или индексов. Этот указатель также отключает объединение индексов и свободное сканирование индекса для таблицы или индексов. По умолчанию доступ по диапазонам — это кандидатская стратегия оптимизации, поэтому указателя для её включения нет.Этот указатель может быть полезен, когда количество диапазонов велико, и оптимизация диапазонов потребует значительных ресурсов.
ORDER_INDEX,NO_ORDER_INDEX: Заставляют MySQL использовать или игнорировать указанный индекс или индексы для сортировки строк. ЭквивалентноFORCE INDEX FOR ORDER BY,IGNORE INDEX FOR ORDER BY.-
SKIP_SCAN,NO_SKIP_SCAN: Включают или выключают метод доступа «Пропуск сканирования» для указанной таблицы или индексов. Дополнительную информацию об этом методе доступа см. в Методе доступа «Пропуск сканирования» для диапазонов.Указатель
SKIP_SCANзаставляет оптимизатор использовать «Пропуск сканирования» для указанной таблицы с использованием указанного набора индексов. Если индекс не указан, оптимизатор рассматривает все возможные индексы и выбирает наименее затратный вариант. Указатель может быть проигнорирован, если индекс неприменим к данному оператору.Указатель
NO_SKIP_SCANотключает «Пропуск сканирования» для указанных индексов. Если указатель не указывает индексы, «Пропуск сканирования» не допускается для таблицы.
tbl_name: Таблица, к которой применяется указатель.-
index_name: Имя индекса в указанной таблице. Указатель применяется ко всем индексам, которые он называет. Если указатель не называет индексы, он применяется ко всем индексам в таблице.Для ссылки на первичный ключ используйте имя
PRIMARY. Для просмотра имён индексов для таблицы используйтеSHOW INDEX. query_block_name: Блок запроса, к которому применяется указатель. Если указатель не содержит ведущего@, указатель применяется к блоку запроса, в котором он находится. Дляquery_block_nameсинтаксиса указатель применяется к указанной таблице в указанном блоке запроса. Для присвоения имени блоку запроса см. Указатели оптимизатора для именования блоков запросов.tbl_name@query_block_name
Примеры:
SELECT /*+ INDEX_MERGE(t1 f3, PRIMARY) */ f2 FROM t1
WHERE f1 = 'o' AND f2 = f3 AND f3 <= 4;
SELECT /*+ MRR(t1) */ * FROM t1 WHERE f2 <= 3 AND 3 <= f3;
SELECT /*+ NO_RANGE_OPTIMIZATION(t3 PRIMARY, f2_idx) */ f1
FROM t3 WHERE f1 > 30 AND f1 < 33;
INSERT INTO t3(f1, f2, f3)
(SELECT /*+ NO_ICP(t2) */ t2.f1, t2.f2, t2.f3 FROM t1,t2
WHERE t1.f1=t2.f1 AND t2.f2 BETWEEN t1.f1
AND t1.f2 AND t2.f2 + 1 >= t1.f1 + 1);
SELECT /*+ SKIP_SCAN(t1 PRIMARY) */ f1, f2
FROM t1 WHERE f2 > 40;
В следующих примерах используются указатели объединения индексов, но другие указатели на уровне индексов следуют тем же принципам в отношении игнорирования указателей и приоритета указателей оптимизатора по отношению к системной переменной optimizer_switch или указателям индексов.
Предположим, что таблица t1 имеет столбцы a, b, c и d; и что индексы с именами i_a, i_b и i_c существуют на a, b и c соответственно:
SELECT /*+ INDEX_MERGE(t1 i_a, i_b, i_c)*/ * FROM t1
WHERE a = 1 AND b = 2 AND c = 3 AND d = 4;
В этом случае используется объединение индексов для (i_a, i_b, i_c).
SELECT /*+ INDEX_MERGE(t1 i_a, i_b, i_c)*/ * FROM t1
WHERE b = 1 AND c = 2 AND d = 3;
В этом случае используется объединение индексов для (i_b, i_c).
/*+ INDEX_MERGE(t1 i_a, i_b) NO_INDEX_MERGE(t1 i_b) */
NO_INDEX_MERGE игнорируется, так как для той же таблицы имеется предшествующий указатель.
/*+ NO_INDEX_MERGE(t1 i_a, i_b) INDEX_MERGE(t1 i_b) */
INDEX_MERGE игнорируется, так как для той же таблицы имеется предшествующий указатель.
Для указателей оптимизатора INDEX_MERGE и NO_INDEX_MERGE действуют следующие правила приоритета:
-
Если указано подсказка оптимизатора и она применима, она имеет приоритет над флагами
optimizer_switchпеременной системной, связанными с Объединением индексов.SET optimizer_switch='index_merge_intersection=off'; SELECT /*+ INDEX_MERGE(t1 i_b, i_c) */ * FROM t1 WHERE b = 1 AND c = 2 AND d = 3;
Подсказка имеет приоритет над
optimizer_switch. В этом случае используется Объединение индексов для(i_b, i_c).SET optimizer_switch='index_merge_intersection=on'; SELECT /*+ INDEX_MERGE(t1 i_b) */ * FROM t1 WHERE b = 1 AND c = 2 AND d = 3;
Подсказка указывает только один индекс, поэтому она неприменима, и применяется флаг
optimizer_switch(on). Объединение индексов используется, если оптимизатор считает это целесообразным с точки зрения затрат.SET optimizer_switch='index_merge_intersection=off'; SELECT /*+ INDEX_MERGE(t1 i_b) */ * FROM t1 WHERE b = 1 AND c = 2 AND d = 3;
Подсказка указывает только один индекс, поэтому она неприменима, и применяется флаг
optimizer_switch(off). Объединение индексов не используется. -
Подсказки оптимизатора уровня индекса
GROUP_INDEX,INDEX,JOIN_INDEXиORDER_INDEXимеют приоритет над эквивалентными подсказкамиFORCE INDEX; то есть, они приводят к игнорированию подсказокFORCE INDEX. Аналогично, подсказкиNO_GROUP_INDEX,NO_INDEX,NO_JOIN_INDEXиNO_ORDER_INDEXимеют приоритет над любыми эквивалентамиIGNORE INDEX, что также приводит к их игнорированию.Подсказки оптимизатора уровня индекса
GROUP_INDEX,NO_GROUP_INDEX,INDEX,NO_INDEX,JOIN_INDEX,NO_JOIN_INDEX,ORDER_INDEXиNO_ORDER_INDEXимеют приоритет над всеми другими подсказками оптимизатора, включая другие подсказки оптимизатора уровня индекса. Любые другие подсказки оптимизатора применяются только к разрешенным этими индексам.Подсказки
GROUP_INDEX,INDEX,JOIN_INDEXиORDER_INDEXэквивалентны подсказкеFORCE INDEX, а не подсказкеUSE INDEX. Это потому, что использование одной или нескольких из этих подсказок означает, что сканирование таблицы используется только в том случае, если нет возможности найти строки в таблице с помощью одного из указанных индексов. Чтобы заставить MySQL использовать тот же индекс или набор индексов, что и с данным экземпляромUSE INDEX, можно использоватьNO_INDEX,NO_JOIN_INDEX,NO_GROUP_INDEX,NO_ORDER_INDEXили их комбинацию.Чтобы воспроизвести эффект, который имеет
USE INDEXв запросеSELECT a,c FROM t1 USE INDEX FOR ORDER BY (i_a) ORDER BY a, можно использовать подсказку оптимизатораNO_ORDER_INDEXдля покрытия всех индексов в таблице, кроме желаемого, вот так:SELECT /*+ NO_ORDER_INDEX(t1 i_b,i_c) */ a,c FROM t1 ORDER BY a;Попытка объединить
NO_ORDER_INDEXдля всей таблицы сUSE INDEX FOR ORDER BYне работает для этого, потому чтоNO_ORDER_BYприводит к игнорированиюUSE INDEX, как показано здесь:mysql>
EXPLAIN SELECT /*+ NO_ORDER_INDEX(t1) */ a,c FROM t1->USE INDEX FOR ORDER BY (i_a) ORDER BY a\G*************************** 1. row *************************** id: 1 select_type: SIMPLE table: t1 partitions: NULL type: ALL possible_keys: NULL key: NULL key_len: NULL ref: NULL rows: 256 filtered: 100.00 Extra: Using filesort -
Подсказки индексов
USE INDEX,FORCE INDEXиIGNORE INDEXимеют более высокий приоритет, чем подсказки оптимизатораINDEX_MERGEиNO_INDEX_MERGE./*+ INDEX_MERGE(t1 i_a, i_b, i_c) */ ... IGNORE INDEX i_a
IGNORE INDEXимеет приоритет надINDEX_MERGE, поэтому индексi_aисключается из возможных диапазонов для Объединения индексов./*+ NO_INDEX_MERGE(t1 i_a, i_b) */ ... FORCE INDEX i_a, i_b
Объединение индексов запрещено для
i_a, i_bиз-заFORCE INDEX, но оптимизатор вынужден использовать либоi_a, либоi_bдля доступаrangeилиref. Конфликтов нет; обе подсказки применимы. Если подсказка
IGNORE INDEXуказывает несколько индексов, эти индексы недоступны для Объединения индексов.-
Подсказки
FORCE INDEXиUSE INDEXделают доступными для Объединения индексов только указанные индексы.SELECT /*+ INDEX_MERGE(t1 i_a, i_b, i_c) */ a FROM t1 FORCE INDEX (i_a, i_b) WHERE c = 'h' AND a = 2 AND b = 'b';
Алгоритм пересечения доступа Объединения индексов используется для
(i_a, i_b). То же самое верно, еслиFORCE INDEXизменено наUSE INDEX.
Подсказки оптимизатора для подзапросов
Подсказки подзапросов влияют на использование преобразований полусоединений и на разрешаемые стратегии полусоединений, а также, когда полусоединения не используются, на использование материализации подзапроса или преобразования IN в EXISTS. Для получения дополнительной информации об этих оптимизациях см. Раздел 10.2.2, «Оптимизация подзапросов, производных таблиц, ссылок на представления и общих табличных выражений».
Синтаксис подсказок, влияющих на стратегии полусоединений:
hint_name([@query_block_name] [strategy [, strategy] ...])
Синтаксис относится к этим терминам:
-
hint_name: Разрешены следующие имена подсказок:SEMIJOIN,NO_SEMIJOIN: Включение или выключение указанных стратегий полусоединений.
-
strategy: Стратегия полусоединения для включения или выключения. Допустимы следующие имена стратегий:DUPSWEEDOUT,FIRSTMATCH,LOOSESCAN,MATERIALIZATION.Для подсказок
SEMIJOIN, если стратегии не указаны, полусоединение используется, если это возможно, на основе стратегий, включенных в соответствии с переменной системыoptimizer_switch. Если стратегии указаны, но неприменимы для оператора, используетсяDUPSWEEDOUT.Для подсказок
NO_SEMIJOIN, если стратегии не указаны, полусоединение не используется. Если указаны стратегии, исключающие все применимые стратегии для оператора, используетсяDUPSWEEDOUT.
Если один подзапрос вложен в другой, и оба объединены в полусоединение внешнего запроса, любые указания стратегий полусоединений для внутреннего подзапроса игнорируются. Подсказки SEMIJOIN и NO_SEMIJOIN по-прежнему могут использоваться для включения или выключения преобразований полусоединений для таких вложенных подзапросов.
Если DUPSWEEDOUT отключено, иногда оптимизатор может сгенерировать план запроса, который далек от оптимального. Это происходит из-за эвристического обрезки во время жадного поиска, чего можно избежать, установив optimizer_prune_level=0.
Примеры:
SELECT /*+ NO_SEMIJOIN(@subq1 FIRSTMATCH, LOOSESCAN) */ * FROM t2
WHERE t2.a IN (SELECT /*+ QB_NAME(subq1) */ a FROM t3);
SELECT /*+ SEMIJOIN(@subq1 MATERIALIZATION, DUPSWEEDOUT) */ * FROM t2
WHERE t2.a IN (SELECT /*+ QB_NAME(subq1) */ a FROM t3);
Синтаксис подсказок, влияющих на то, использовать ли материализацию подзапроса или преобразования IN-to-EXISTS:
SUBQUERY([@query_block_name] strategy)
Имя подсказки всегда SUBQUERY.
Для подсказок SUBQUERY допустимы следующие значения strategy: INTOEXISTS, MATERIALIZATION.
Примеры:
SELECT id, a IN (SELECT /*+ SUBQUERY(MATERIALIZATION) */ a FROM t1) FROM t2;
SELECT * FROM t2 WHERE t2.a IN (SELECT /*+ SUBQUERY(INTOEXISTS) */ a FROM t1);
Для подсказок полусоединения и SUBQUERY ведущее @ указывает блок запроса, к которому относится подсказка. Если подсказка не содержит ведущего query_block_name@, подсказка относится к блоку запроса, в котором она находится. Для присвоения имени блоку запроса см. Подсказки оптимизатора для именования блоков запросов. query_block_name
Если комментарий подсказки содержит несколько подсказок для подзапросов, используется первая. Если есть другие следующие подсказки такого типа, они вызывают предупреждение. Следующие подсказки других типов игнорируются.
Указания оптимизатора для времени выполнения оператора
Указание MAX_EXECUTION_TIME разрешено только для операторов SELECT. Оно устанавливает ограничение N (значение таймаута в миллисекундах) на время выполнения оператора, прежде чем сервер его прервет:
MAX_EXECUTION_TIME(N)
Пример с таймаутом в 1 секунду (1000 миллисекунд):
SELECT /*+ MAX_EXECUTION_TIME(1000) */ * FROM t1 INNER JOIN t2 WHERE ...
Указание MAX_EXECUTION_TIME( устанавливает таймаут выполнения оператора в N)N миллисекунд. Если этот параметр отсутствует или N равно 0, применяется таймаут оператора, установленный системной переменной max_execution_time.
Указание MAX_EXECUTION_TIME применяется следующим образом:
Для операторов с несколькими ключевыми словами
SELECT, такими как объединения или операторы с подзапросами, указаниеMAX_EXECUTION_TIMEприменяется ко всему оператору и должно появляться после первого оператораSELECT.Оно применяется к операторам чтения
SELECTтолько для чтения. Операторы, которые не являются только для чтения, — это те, которые вызывают хранимую функцию, изменяющую данные как побочный эффект.Оно не применяется к операторам
SELECTв хранимых программах и игнорируется.
Синтаксис указания установки переменной
Указание SET_VAR временно устанавливает значение системной переменной в сеансе (на время выполнения одного оператора). Примеры:
SELECT /*+ SET_VAR(sort_buffer_size = 16M) */ name FROM people ORDER BY name;
INSERT /*+ SET_VAR(foreign_key_checks=OFF) */ INTO t2 VALUES(2);
SELECT /*+ SET_VAR(optimizer_switch = 'mrr_cost_based=off') */ 1;
Синтаксис указания SET_VAR:
SET_VAR(var_name = value)
var_name указывает имя системной переменной, имеющей значение в сеансе (хотя не все такие переменные можно назвать, как объяснено позже). value — это значение, которое нужно присвоить переменной; значение должно быть скалярным.
SET_VAR производит временное изменение переменной, как показано в этих операторах:
mysql> SELECT @@unique_checks;
+-----------------+
| @@unique_checks |
+-----------------+
| 1 |
+-----------------+
mysql> SELECT /*+ SET_VAR(unique_checks=OFF) */ @@unique_checks;
+-----------------+
| @@unique_checks |
+-----------------+
| 0 |
+-----------------+
mysql> SELECT @@unique_checks;
+-----------------+
| @@unique_checks |
+-----------------+
| 1 |
+-----------------+
С SET_VAR нет необходимости сохранять и восстанавливать значение переменной. Это позволяет заменить несколько операторов одним оператором. Рассмотрим эту последовательность операторов:
SET @saved_val = @@SESSION.var_name;
SET @@SESSION.var_name = value;
SELECT ...
SET @@SESSION.var_name = @saved_val;
Последовательность можно заменить этим одиночным оператором:
SELECT /*+ SET_VAR(var_name = value) ...
Операторы SET позволяют использовать любой из этих синтаксисов для именования переменных сеанса:
SET SESSION var_name = value;
SET @@SESSION.var_name = value;
SET @@.var_name = value;
Поскольку указание SET_VAR применяется только к переменным сеанса, область действия сеанса неявна, и SESSION, @@SESSION. и @@ не нужны и не разрешены. Включение явного синтаксиса индикатора сеанса приведет к игнорированию указания SET_VAR с предупреждением.
Не все переменные сеанса разрешены для использования с SET_VAR. В описаниях отдельных системных переменных указано, разрешена ли каждая переменная для указаний; см. Раздел 7.1.8, «Системные переменные сервера». Вы также можете проверить системную переменную во время выполнения, попытавшись использовать ее с SET_VAR. Если переменная не разрешена для указаний, появляется предупреждение:
mysql> SELECT /*+ SET_VAR(collation_server = 'utf8mb4') */ 1;
+---+
| 1 |
+---+
| 1 |
+---+
1 row in set, 1 warning (0.00 sec)
mysql> SHOW WARNINGS\G
*************************** 1. row ***************************
Level: Warning
Code: 4537
Message: Variable 'collation_server' cannot be set using SET_VAR hint.
Синтаксис SET_VAR позволяет установить только одну переменную, но можно использовать несколько указаний для установки нескольких переменных:
SELECT /*+ SET_VAR(optimizer_switch = 'mrr_cost_based=off')
SET_VAR(max_heap_table_size = 1G) */ 1;
Если несколько указаний с одним и тем же именем переменной появляются в одном операторе, применяется первое, а остальные игнорируются с предупреждением:
SELECT /*+ SET_VAR(max_heap_table_size = 1G)
SET_VAR(max_heap_table_size = 3G) */ 1;
В этом случае второе указание игнорируется с предупреждением о конфликте.
Указание SET_VAR игнорируется с предупреждением, если нет системной переменной с указанным именем или значение переменной некорректно:
SELECT /*+ SET_VAR(max_size = 1G) */ 1;
SELECT /*+ SET_VAR(optimizer_switch = 'mrr_cost_based=yes') */ 1;
Для первого оператора нет переменной max_size. Для второго оператора mrr_cost_based принимает значения on или off, поэтому попытка установить ее в yes некорректна. В каждом случае указание игнорируется с предупреждением.
Указание SET_VAR разрешено только на уровне оператора. Если используется в подзапросе, указание игнорируется с предупреждением.
Реплики игнорируют указания SET_VAR в реплицированных операторах, чтобы избежать потенциальных проблем безопасности.
Синтаксис указания группы ресурсов
Указание оптимизатора RESOURCE_GROUP используется для управления группами ресурсов (см. Раздел 7.1.16, «Группы ресурсов»). Это указание временно (на время выполнения оператора) назначает поток, выполняющий оператор, указанной группе ресурсов. Требуется привилегия RESOURCE_GROUP_ADMIN или RESOURCE_GROUP_USER.
Примеры:
SELECT /*+ RESOURCE_GROUP(USR_default) */ name FROM people ORDER BY name;
INSERT /*+ RESOURCE_GROUP(Batch) */ INTO t2 VALUES(2);
Синтаксис указания RESOURCE_GROUP:
RESOURCE_GROUP(group_name)
group_name указывает группу ресурсов, которой должен быть назначен поток на время выполнения оператора. Если группы не существует, появляется предупреждение, и указание игнорируется.
Указание RESOURCE_GROUP должно появляться после начального ключевого слова оператора (SELECT, INSERT, REPLACE, UPDATE или DELETE).
Альтернативой RESOURCE_GROUP является оператор SET RESOURCE GROUP, который постоянно назначает потоки группе ресурсов. См. Раздел 15.7.2.4, «Оператор SET RESOURCE GROUP».
Указания оптимизатору для именования блоков запросов
Указания оптимизатора на уровне таблиц, индексов и подзапросов позволяют именовать отдельные блоки запросов в качестве аргументов. Для создания этих имён используйте указание QB_NAME, которое присваивает имя блоку запроса, в котором оно используется:
QB_NAME(name)
Указания QB_NAME позволяют чётко указать, к каким блокам запросов относятся другие указания. Они также позволяют указать все указания, не связанные с именами блоков запросов, в одном комментарии к указаниям, что упрощает понимание сложных операторов. Рассмотрим следующий оператор:
SELECT ...
FROM (SELECT ...
FROM (SELECT ... FROM ...)) ...
Указания QB_NAME присваивают имена блокам запросов в операторе:
SELECT /*+ QB_NAME(qb1) */ ...
FROM (SELECT /*+ QB_NAME(qb2) */ ...
FROM (SELECT /*+ QB_NAME(qb3) */ ... FROM ...)) ...
Затем другие указания могут использовать эти имена для ссылки на соответствующие блоки запросов:
SELECT /*+ QB_NAME(qb1) MRR(@qb1 t1) BKA(@qb2) NO_MRR(@qb3t1 idx1, id2) */ ...
FROM (SELECT /*+ QB_NAME(qb2) */ ...
FROM (SELECT /*+ QB_NAME(qb3) */ ... FROM ...)) ...
Результат следующий:
MRR(@qb1 t1)относится к таблицеt1в блоке запросаqb1.BKA(@qb2)относится к блоку запросаqb2.NO_MRR(@qb3 t1 idx1, id2)относится к индексамidx1иidx2в таблицеt1в блоке запросаqb3.
Имена блоков запросов являются идентификаторами и следуют обычным правилам относительно допустимых имён и способа их цитирования (см. Раздел 11.2, «Имена объектов схемы»). Например, имя блока запроса, содержащее пробелы, должно быть заключено в кавычки, что можно сделать с помощью обратных кавычек:
SELECT /*+ BKA(@`my hint name`) */ ...
FROM (SELECT /*+ QB_NAME(`my hint name`) */ ...) ...
Если включён режим SQL ANSI_QUOTES, можно также заключить имя блока запроса в двойные кавычки:
SELECT /*+ BKA(@"my hint name") */ ...
FROM (SELECT /*+ QB_NAME("my hint name") */ ...) ...
© 2025 Oracle
Licensed under the GPLv2 License.