key列显示实际使用的索引,possible_keys列显示可能用到的索引;若possible_keys非空而key为null,说明索引未被选用,通常因where条件未满足最左前缀原则。
看执行计划里的 key 和 possible_keys 是否匹配
执行计划是唯一能告诉你“索引有没有被用上”的依据。右键 sql → “解释”,重点盯两列:key(实际用的索引)和 possible_keys(可能用的索引)。如果 possible_keys 有值但 key 是空的,说明索引存在,但没被选中——大概率是字段顺序不匹配 where 条件的最左前缀。
常见错误现象:
- 建了
INDEX(status, created_at),但查询写成WHERE created_at > '2024-01-01' AND status = 'active',key为空 - 建了
INDEX(user_id, order_status),但只查WHERE order_status = 'shipped',优化器直接跳过该索引
真正起作用的不是“包含这些字段”,而是“最左边的字段是否被等值过滤”。只要第一个字段没出现在 WHERE 中做 =、IN 或 IS NULL,后续字段全失效。
对照 SHOW INDEX FROM table_name 确认物理顺序
别信索引名,也别靠肉眼猜。运行 SHOW INDEX FROM orders,看 Seq_in_index 列:它才是字段在索引里的真实位置。比如输出里 status 的 Seq_in_index 是 1,created_at 是 2,那这个索引就只能支持 WHERE status = ? 或 WHERE status = ? AND created_at > ? 这类查询。
容易踩的坑:
- Navicat 设计表界面里拖拽字段顺序 ≠ 实际建索引顺序——保存前务必点“预览 SQL”,确认生成语句是
KEY idx_xxx (col_a, col_b)而不是反着的 - MySQL 8.0+ 支持
DESC显式排序,但 InnoDB 早期版本忽略它;Seq_in_index不体现方向,只体现位置
用高频查询反推最左字段应优先放什么
索引字段顺序不是按字母排,也不是按建表顺序排,而是按你最常写的 WHERE 条件来排。原则就一条:等值条件字段放最左,范围条件(BETWEEN、>、LIKE 'abc%')放右边,ORDER BY 字段能接在后面就接,不能接就另建。
典型场景:
-
WHERE tenant_id = ? AND status IN (?, ?) ORDER BY created_at DESC→ 合理索引是(tenant_id, status, created_at) -
WHERE created_at > ? AND status = ?→status必须放最左,否则索引无法启动 -
WHERE email LIKE 'a%'单独出现 →email单列索引即可,不用塞进复合索引
注意:低选择性字段(如只有 2–3 个值的 is_deleted)单独放最左几乎没意义,除非搭配高选择性字段一起用。
留意 Navicat 自身渲染行为干扰判断
你看到“查询慢”,不一定是索引没生效,可能是 Navicat 在本地处理大量结果。比如 SELECT * FROM logs WHERE level = 'ERROR' LIMIT 20,如果匹配 50 万行,Navicat(尤其 ≤16.0 版本)会先拉全量再截取,导致卡顿、内存爆满、甚至误判为“索引无效”。
验证方法:
- 改用命令行或
mysql -e "EXPLAIN ..."看原始输出,避开 GUI 渲染干扰 - 在 Navicat 中右键 SQL → “在新标签页中运行”,勾选「限制行数」并设为 1,观察
rows值是否显著下降 - 检查
type是否为ALL:如果是,且表行数远大于几万,基本可断定没走索引
真正的难点不在“怎么建”,而在“建完之后,你得用对的查询去触发它”。字段顺序一旦定死,改起来要 DROP INDEX + CREATE INDEX,没有热更新。每次加索引前,先翻慢日志,挑出 top 3 查询,把它们的 WHERE 和 ORDER BY 拆开看最左字段共性——这才是最省事的做法。











