9 ноября 2026 года на блоге MariaDB.org вышел разбор хинтов оптимизатора в Server 13.0. Текст написал Олег Смирнов, старший инженер MariaDB plc. Страницу подписал Фредерик Декамп, рубрика Using MariaDB.

Хинт живёт в тексте одного SQL-запроса, обычным комментарием. Им можно подсказать оптимизатору порядок соединения, индекс или отдельный приём, когда про данные известно то, чего оптимизатор не видит. Из-за такого комментария MariaDB не перезапускают. nginx и php-fpm тоже не трогают.
Синтаксис /*+ */ как в MySQL 8.0
MariaDB взяла запись, которую MySQL ввёл в версии 8.0. Тот же вид комментария использует TiDB. Сразу после SELECT стоит /*+ ... */. Внутри одна или несколько подсказок. Так помечают и внешний запрос, и вложенный SELECT.
SELECT /*+ hint1(arguments) hint2(arguments) */ ... FROM t1 WHERE a IN (SELECT /*+ hint3(arguments) */ ...);
Имена hint1 и hint3 в этом фрагменте учебные: так пример и записан у MariaDB. В рабочий запрос ставят конкретный хинт, не эти заглушки.
Подсказкой можно управлять вот чем:
- в каком порядке соединять таблицы;
- какой индекс брать, а какой не трогать;
- пользоваться ли буфером соединения (join buffer);
- раскрывать ли подзапрос в
FROMи вливать его в основной запрос; - передавать ли условие внутрь такого подзапроса;
- как выполнять подзапрос;
- включать ли отдельные приёмы: MRR, ICP, поиск по диапазону, фильтр по rowid, lateral derived;
- сколько запросу можно работать. За это отвечает хинт
MAX_EXECUTION_TIME.
Имена хинтов у MariaDB и MySQL почти совпадают, мелкие отличия есть. В представление MySQL пускает не всё. Полный список с примерами собран в документации MariaDB. Если хинт ведёт себя не так или нужной подсказки нет, тикет просят открывать в Jira MariaDB.
В VIEW можно не только индекс
В определении представления MySQL разрешает только индексные хинты. Пример из разбора выглядит так:
CREATE VIEW v1 AS SELECT /*+ NO_INDEX(t1) */ a FROM t1;
NO_INDEX(t1) запрещает индексный доступ к t1. Другие подсказки MySQL в тело VIEW не берёт.
В MariaDB такого ограничения нет. В CREATE VIEW можно поставить любые хинты, кроме MAX_EXECUTION_TIME. Второй пример из того же разбора, таблицы учебные:
CREATE VIEW v1 AS SELECT /*+ NO_MRR(t1 idx_a) JOIN_ORDER(t2, t1)*/ t1.a, t2.a FROM t1, t2 WHERE t1.a = t2.b;
Здесь две подсказки сразу. NO_MRR(t1 idx_a) отключает приём MRR для индекса idx_a на таблице t1. JOIN_ORDER(t2, t1) задаёт порядок соединения: сначала t2, потом t1. Связь в примере обычная, t1.a = t2.b.

Хинт внутри представления может называть только объекты этого представления. Таблицу снаружи вписать нельзя. Лимит времени туда тоже не кладут. MAX_EXECUTION_TIME пишут в том запросе, который запускают сейчас, а не в CREATE VIEW.
На сайте с WordPress ядро такие представления не создаёт. Запросы к таблицам wp_* идут как раньше. Хинт нужен, когда своё представление или тяжёлый отчёт стабильно выбирает плохой план и уже понятно, что именно поправить. Зашили JOIN_ORDER или NO_MRR в VIEW, и подсказка остаётся в определении. Каждый следующий запрос через это представление её подхватит.
Перед заменой определения сохраните текущий текст. Команда SHOW CREATE VIEW и обычный дамп схемы. Пример с t1, t2 и idx_a на боевую базу не переносят: таких имён у WordPress нет.
Представление, перенесённое с MySQL, где внутри был только NO_INDEX, на MariaDB 13.0 читается тем же синтаксисом. Обратный путь уже теснее. JOIN_ORDER и NO_MRR внутри VIEW MySQL в определение представления не берёт, там остаются индексные хинты. Если одна схема живёт и на MariaDB, и на MySQL, подсказки внутри VIEW проверяют на той стороне, куда поедет дамп.
Имя блока запроса без QB_NAME
Вторая своя добавка MariaDB. Чтобы обратиться к внутреннему куску запроса, не обязательно вставлять в него хинт QB_NAME. Сервер понимает явное имя блока, имя по позиции в тексте запроса и имя по алиасу.
Самый гибкий способ: явное имя с путём. Им можно указать объект внутри представления, производной таблицы, общего табличного выражения (CTE) или подзапроса и не дописывать QB_NAME в их текст. Идею пути в MariaDB связывают с TiDB. Там тоже нужно было дотянуться до объекта во внутреннем блоке, не правя сам блок.
Как записывается путь, показано в документации MariaDB, рядом с остальными примерами хинтов.
Хинты есть в Server 13.0
Разбор относится к текущему выпуску MariaDB Server 13.0. Пока версия сервера ниже 13.0, примеры к этой базе не относятся. Сначала смотрят номер, потом копируют комментарий в запрос.
mariadb --version
В клиенте то же самое показывает SELECT VERSION(). В выводе нужна ветка 13.0.
Нет 13.0 в строке версии, значит переписывать запросы сайта рано. Переводить рабочую базу WordPress на новую ветку только ради комментария в SQL незачем. MariaDB прямо пишет, что хинты не замена нормальному оптимизатору. Это рычаг, когда план уже не устраивает.
Путаются обычно в трёх местах. Хинт остался внутри VIEW, а план смотрят по тем же таблицам без представления и не узнают его. В подсказке указана таблица, которой внутри VIEW нет. MAX_EXECUTION_TIME уехал в определение представления, хотя туда его ставить нельзя.
На типичном сайте с WordPress комментарий появляется в своём SQL и только когда сервер уже MariaDB 13.0. Конфиг nginx и wp-config.php из-за этих хинтов не меняют. Если план и так нормальный, комментарий /*+ */ лучше не добавлять.

