MySQL

MySQL Optimizer Hints: INDEX, JOIN_ORDER, and MAX_EXECUTION_TIME

Guide MySQL query execution with optimizer hints. Covers INDEX, NO_INDEX, JOIN_ORDER, MAX_EXECUTION_TIME, and query block naming for subquery hint targeting.

JusDB Team
Published October 27, 2025
Updated August 1, 2026
5 min read

MySQL provides SQL-level optimizer hints that let you guide query execution plans without changing application code or server configuration.

Hint Syntax

sql
-- Hints go in a comment immediately after SELECT/INSERT/UPDATE/DELETE
SELECT /*+ hint_name(args) */ columns FROM table;

Index Hints

sql
-- Force a specific index
SELECT /*+ INDEX(orders idx_orders_created_at) */
  id, amount FROM orders WHERE created_at > '2025-01-01';

-- Force no index (full table scan)
SELECT /*+ NO_INDEX(orders idx_orders_status) */
  * FROM orders WHERE status = 'active';

-- Force index for ORDER BY (avoid filesort)
SELECT /*+ INDEX_ORDER(orders idx_orders_created_at) */
  * FROM orders ORDER BY created_at DESC LIMIT 100;

Join Order Hints

sql
-- Force join order (drive from orders, then join users)
SELECT /*+ JOIN_ORDER(orders, users) */
  o.id, u.email
FROM orders o JOIN users u ON o.user_id = u.id
WHERE o.status = 'pending';

-- Force nested loop join
SELECT /*+ JOIN_FIXED_ORDER() BNL(orders, users) */
  o.id, u.email
FROM orders o JOIN users u ON o.user_id = u.id;

Resource Group Hint

sql
-- Run query in a resource group (MySQL 8.0+)
SELECT /*+ RESOURCE_GROUP(analytics_group) */
  region, sum(amount) FROM orders GROUP BY region;

MAX_EXECUTION_TIME

sql
-- Kill query if it takes more than 5 seconds
SELECT /*+ MAX_EXECUTION_TIME(5000) */
  * FROM large_table WHERE complex_condition;

Query Block Naming

sql
-- Name subquery blocks to apply hints to them
SELECT /*+ QB_NAME(outer) */
  id FROM orders
WHERE user_id IN (
  SELECT /*+ QB_NAME(inner) INDEX(users idx_users_status) */ id
  FROM users WHERE status = 'premium'
);

Key Takeaways

  • Use hints to fix bad plans without changing server configuration that affects all queries
  • MAX_EXECUTION_TIME is a safety net for queries that might run away
  • Test hints with EXPLAIN first — a hint can make things worse if applied to the wrong query
  • Hints should be a last resort — fix statistics and indexes first

Use Hints as a Controlled Exception

A hint is a plan constraint embedded in application SQL, so it can outlive the data distribution that justified it. First capture the unhinted SQL digest, plan, estimates, actual row counts, latency distribution, and relevant statistics. Refresh stale statistics and check index design before adding a hint. Write down the exact regression the hint mitigates and an expiry or review condition. Without that record, a temporary fix becomes an invisible permanent dependency. Reproduce the issue before and after refreshing statistics so transient cache or concurrency noise is not mistaken for a plan defect.

Target the Correct Object

Optimizer hints belong in the /*+ ... */ comment immediately after the initial statement keyword. When a table has an alias, table and join hints must name the alias, not the base table; schema-qualified table names are not accepted inside hints. For nested SQL, assign stable names with QB_NAME and target the intended block explicitly. This matters because transformations can merge subqueries or derived tables into another block. Index-hint families have version history, so verify syntax against the deployed release rather than assuming an example for a newer 8.0 or 8.4 server works on an older one.

EXPLAIN SELECT /*+ JOIN_ORDER(o, u) JOIN_INDEX(o idx_orders_status) */ o.id, u.email FROM orders AS o JOIN users AS u ON u.id = o.user_id WHERE o.status = 'pending';
SHOW WARNINGS;

Confirm That MySQL Accepted the Hint

MySQL can ignore duplicate, conflicting, impossible, or inapplicable hints, sometimes with a warning and sometimes silently. Outer-join dependencies and const tables can prevent a requested join order. Run SHOW WARNINGS immediately after EXPLAIN, inspect extended or JSON plan output, and verify the chosen access paths rather than treating valid syntax as proof of effect. In MySQL 8.4, BNL and NO_BNL control hash-join optimization; HASH_JOIN and NO_HASH_JOIN themselves have no effect. That version detail is a strong reason to pin tests to the actual server version.

Benchmark Representative Shapes

Test common, rare, empty, and highly skewed parameter values. Compare rows estimated with rows examined, execution time, temporary tables, sort work, buffer reads, lock time, and concurrency. EXPLAIN ANALYZE executes the statement, so run it on a safe read-only query and an environment where its load is acceptable. A forced index can be excellent for a selective value and disastrous for a common one; a fixed join order can age badly as table sizes reverse. Include the no-hint query in every test so the optimizer can prove when it has become better than the workaround.

Understand the Timeout Boundary

MAX_EXECUTION_TIME(N) uses milliseconds, applies to the whole read-only SELECT, and must appear after the first SELECT when subqueries or unions are present. It is ignored for SELECT inside stored programs and is not a transaction timeout. Treat it as a guardrail, not capacity control: an aborted query may already have consumed substantial CPU or I/O, and callers still need cancellation and retry handling.

Rollout, Monitoring, and Removal

Canary the hinted statement by application version or traffic slice. Monitor plan shape, query errors, rows examined, latency percentiles, and data growth. Keep rollback as a code or configuration switch that restores the original SQL; do not bundle the hint with unrelated schema changes. Re-evaluate after upgrades, major loads, index changes, or statistics changes. Remove the hint when the unhinted plan is consistently equivalent or better across representative inputs. A hint has succeeded operationally when it is measurable, reversible, and temporary.

Official MySQL References

JusDB Can Help

MySQL query optimization often requires a combination of hints, statistics, and index design. JusDB can identify and fix your most problematic queries permanently.

Share this article

JusDB Team

Official JusDB content team

Keep reading

MySQL Explained (2026): InnoDB, 8.4 LTS, Replication & Production Patterns

Everything you need to know about MySQL: storage engines, replication topologies, performance tuning, and cloud deployment. From basics to advanced optimization.

MySQL9 minMay 13, 2026
Read

MySQL binlog Retention, Rotation & Purge: Production Guide (2026)

Configure MySQL binlog retention safely: binlog_expire_logs_seconds, manual purging rules, AWS RDS retention, and the disk-exhaustion failure mode you should monitor for.

MySQL10 minMay 9, 2026
Read

MySQL "Communications Link Failure": Fix wait_timeout, HikariCP & All 8 Timeout Variables

MySQL wait_timeout, net_read_timeout, innodb_lock_wait_timeout and max_execution_time — production tuning rules and the HikariCP alignment trick that prevents 'communications link failure' errors.

MySQL6 minMay 9, 2026
Read