今天我们聊聊 MySQL 8.0 中的优化器提示功能,为什么会有MySQL 优化器提示呢。 大家可能之前都遇到过慢SQL
,并且惊讶的发现 MySQL 选错了索引或者当表数据发生大量变更后,优化器依赖的索引选择性、表行数等统计信息可能不再准确,导致它选错索引。为了解决这个问题,MySQL 引入了一种优化器提示功能,通俗的说,就是告诉MySQL Server 在执行SQL的时候 如何选择索引。
具体原文在官网的10.9.3 章节。https://dev.mysql.com/doc/refman/8.0/en/optimizer-hints.html
什么时候使用优化器提示
定位问题:先用
EXPLAIN发现优化器选错了执行计划(如该用索引却全表扫描)。选对提示:根据问题选对应的提示(如
INDEX_MERGE、BKA)。验证效果:再用
EXPLAIN看执行计划是否改变,并用SET TIMING ON对比查询耗时。一句话总结优化器提示是“人工干预数据库执行策略”的工具,能用在优化器“犯糊涂”时拉它一把,但别把它当成替代合理索引设计的“万能药”。

优化器提示(Optimizer Hints)是数据库领域的重要功能,不同数据库管理系统引入该功能的版本存在差异。以下为你介绍主流数据库中优化器提示的引入版本及相关内容:
引入版本
MySQL 5.6首次引入了部分优化器提示功能,但功能相对有限。MySQL 8.0对优化器提示进行了大幅增强,支持更多类型的提示,使其更灵活和实用。
1. 常见优化器提示示例
在 MySQL 中,优化器提示通过 /*+ */ 语法添加到 SQL 语句中,例如:
SELECT /*+ HINT_NAME */ column1, column2
FROM table1
JOIN table2 ON table1.id = table2.id;
USE INDEX:指定查询使用的索引
SELECT * FROM orders /*+ USE INDEX(idx_order_date) */ WHERE order_date > '2023-01-01';IGNORE INDEX:忽略指定的索引
SELECT * FROM customers /*+ IGNORE INDEX(idx_customer_name) */ WHERE customer_name LIKE 'A%';FORCE INDEX:强制使用指定的索引
SELECT * FROM products /*+ FORCE INDEX(primary) */ WHERE product_id = 100;
2. 核心本质用提示覆盖优化器的默认决策
数据库优化器会根据统计信息(如索引选择性、表大小)自动选择执行计划,但它的判断可能出错:
场景1:索引存在但优化器没选(如统计信息过时)。
场景2:多个索引可用,优化器选了低效的那个。
场景3:需要临时修改数据库行为(如禁用外键检查)。
优化器提示的作用就是:强制指定执行策略,覆盖优化器的自动选择。
3. 用提示“指挥”数据库干活
unsetunset例子:查“25-35岁”或“活跃”的用户(索引合并场景)unsetunset
假设表结构:
CREATE TABLE users (
id INT PRIMARY KEY,
age INT,
status VARCHAR(20),
-- 索引:年龄和状态各有一个索引
KEY idx_age(age),
KEY idx_status(status)
);
unsetunset1. 无提示:优化器可能的选择unsetunset
-- 正常查询:优化器可能选全表扫描或单个索引
SELECT * FROM users WHERE age BETWEEN 25 AND 35 OR status = 'active';
问题:如果age和status的条件都有很多结果,单个索引可能效率低,优化器却没意识到可以合并索引。
unsetunset2. 加提示:强制合并两个索引unsetunset
-- 用INDEX_MERGE提示告诉优化器:“合并两个索引扫描!”
SELECT /*+ INDEX_MERGE(users idx_age, idx_status) */ *
FROM users
WHERE age BETWEEN 25 AND 35 OR status = 'active';
执行过程:
优化器被迫同时扫描
idx_age(查25-35岁)和idx_status(查活跃用户)。把两个结果合并(类似“OR”的并集),再取数据,比单个索引更高效。
4. 常见提示类型解决不同场景
6. 如何验证提示生效?—— 用EXPLAIN查看数据库的执行计划
EXPLAIN SELECT /*+ INDEX_MERGE(users idx_age, idx_status) */ *
FROM users
WHERE age BETWEEN 25 AND 35 OR status = 'active';
type列显示index_merge→ 确认使用索引合并。key列显示idx_age,idx_status→ 确认用了指定的两个索引。Extra列显示Using union(...)→ 确认是“OR”条件的并集合并。
评论区