EXPLAIN显示type=ALL表示全表扫描,响应慢,主因是缺索引、函数操作或隐式转换;应结合rows和filtered评估、按最左前缀建联合索引、优先等值条件、善用覆盖索引并定期更新统计信息。

为什么 EXPLAIN 显示 type=ALL 就该警惕
这表示 MySQL 正在执行全表扫描,即逐行读取整张表来匹配条件。哪怕只有几万行,一旦并发上来或字段含大文本,响应就会明显变慢。常见诱因是 WHERE 条件列没索引、用了函数(如 WHERE YEAR(created_at) = 2023)、或隐式类型转换(比如对字符串字段传数字值)。
- 用
EXPLAIN FORMAT=TREE查看更直观的执行路径,注意rows和filtered的乘积是否远超实际返回行数 - 避免在索引列上使用
!=、NOT IN、LIKE '%abc'—— 这些基本无法走索引 - 联合索引要注意最左前缀:如果建了
(a, b, c),那WHERE b = ?或WHERE c = ?是不会命中索引的
如何判断该加单列索引还是联合索引
单列索引适合高频独立查询的字段,比如 user_id、status;联合索引则要按「查询频率高 + 过滤性强 + 出现在 WHERE 最左侧」的顺序排列。MySQL 8.0+ 支持降序索引,但 ORDER BY a ASC, b DESC 需显式声明 (a ASC, b DESC) 才能完全覆盖排序。
- 优先把等值条件列放前面,范围查询(
>,BETWEEN)放后面,ORDER BY列尽量接在最后 - 例如查询
SELECT * FROM orders WHERE shop_id = ? AND status = ? ORDER BY created_at DESC,推荐索引为(shop_id, status, created_at) - 别盲目给所有
WHERE字段都建索引——索引越多,写入越慢,且优化器可能选错执行计划
SELECT * 和覆盖索引的关系
如果一个查询的所有字段都能从索引中直接获取(即「覆盖索引」),MySQL 就不必回表查聚簇索引,性能提升显著。但前提是这些字段必须全部出现在同一个索引的「叶子节点」里。
CWMS 2.0功能介绍:一、 员工考勤系统,国内首创CWMS2.0的企业员工在线考勤系统。二、 自定义URL Rewrite重写,友好的搜索引擎 URL优化。三、 代码与模板分离技术,支持超过5种类型的模板类型。包括:文章、图文、产品、单页、留言板。四、 购物车功能,CWMS2.0集成国内主流支付接口。如:淘宝、易趣、快钱等。完全可媲美专业网上商城系统。五、 多语言自动切换 中英文的说明。六、
- 例如有索引
(user_id, email, created_at),那么SELECT user_id, email FROM users WHERE user_id = ?就是覆盖索引查询 - 但
SELECT *几乎不可能被覆盖,因为主键以外的字段(尤其是TEXT、BLOB)不会存进二级索引 - 用
EXPLAIN看Extra列是否含Using index,有就是覆盖了;若出现Using index condition,说明用了 ICP(索引条件下推),也比全表扫描强
哪些场景下索引会失效或被忽略
即使建了索引,MySQL 也可能不走它。典型情况包括:统计信息过期、索引选择性太低(比如 gender 只有 'M'/'F')、查询返回大量行(优化器认为全表扫描反而更快)、或者存在更优的索引被误选。
- 运行
ANALYZE TABLE table_name更新统计信息,尤其在大批量导入后 - 对低基数字段(如状态码、开关标志)建索引意义不大,除非配合高选择性条件(如
WHERE status = 'processing' AND updated_at > NOW() - INTERVAL 1 HOUR) - 用
FORCE INDEX是临时手段,不能替代问题定位;真正要查的是为什么优化器没选对——通常得结合SHOW INDEX和EXPLAIN对比评估
EXPLAIN SELECT id, name FROM users WHERE deleted = 0 AND created_at > '2024-01-01';
索引设计不是一劳永逸的事。表结构变、数据分布变、查询模式变,原来高效的索引可能变成瓶颈。重点不是堆索引,而是理解每条慢查询背后的访问路径和数据特征。









