MySQL优化器基于选择性决定是否使用索引,低选择性字段(如95%值相同)可能触发全表扫描;联合索引需按过滤强度排序,首列必须匹配才能生效;DISTINCT、JOIN、LIKE等操作易导致索引失效;冗余或未使用的索引应及时清理。

为什么 WHERE 条件用了索引,但执行计划还是走全表扫描?
常见错觉是“只要字段有索引,查询就一定用上”。实际 MySQL 优化器会评估 WHERE 条件的 选择性(selectivity):如果数据分布极度倾斜(比如 status 字段 95% 是 'active'),即使该字段有索引,优化器也可能判定走索引+回表的成本高于直接全表扫描。
- 用
SELECT COUNT(*) FROM t WHERE status = 'active';和SELECT COUNT(*) FROM t;对比,估算选择性是否低于 5%~10% - 执行
EXPLAIN后重点看type列:若为ALL或index,说明未命中有效索引;再看rows是否接近总行数 - 对低选择性字段,单独建索引意义不大;可考虑与高选择性字段组合成联合索引,把低选择性字段放在后面
联合索引中字段顺序怎么排才不白建?
联合索引 (a, b, c) 实际只等价于三个索引:(a)、(a,b)、(a,b,c),并不支持跳过前导列的查询(如 WHERE b = ? 或 WHERE b = ? AND c = ?)。
- 把 过滤性最强 的字段放最左:比如用户表中
user_id(唯一)比city(重复多)更适合做首列 - 把常用于
ORDER BY或GROUP BY的字段靠右放置,可避免Using filesort;例如查询WHERE category = ? ORDER BY created_at DESC,索引应为(category, created_at) - 注意
IN和范围查询(>,BETWEEN)会截断后续字段的索引使用:在(a, b, c)上执行WHERE a = 1 AND b > 10 AND c = 5,只有a和b能用索引,c不会生效
DISTINCT、JOIN 和 LIKE 查询怎么避开索引失效?
这三类操作极易触发索引退化,不是语法写错,而是语义导致无法利用 B+ 树结构。
Magento是一套专业开源的PHP电子商务系统。Magento设计得非常灵活,具有模块化架构体系和丰富的功能。易于与第三方应用系统无缝集成。Magento开源网店系统的特点主要分以下几大类,网站管理促销和工具国际化支持SEO搜索引擎优化结账方式运输快递支付方式客户服务用户帐户目录管理目录浏览产品展示分析和报表Magento 1.6 主要包含以下新特性:•持久性购物 - 为不同的
-
DISTINCT在无WHERE时通常需要扫描全部索引或数据页;若仅需去重某几列,确保这些列本身构成覆盖索引,例如SELECT DISTINCT a, b FROM t可用(a, b)索引避免回表 -
JOIN中被驱动表(即EXPLAIN中type为ref/eq_ref的那张)的关联字段必须有索引;且类型要严格一致——VARCHAR(50)关联VARCHAR(100)可能因隐式转换失效 -
LIKE以通配符开头(LIKE '%abc')必然无法使用索引;若必须前缀模糊,考虑全文索引(FULLTEXT)或倒排表;LIKE 'abc%'是安全的,前提是字段没参与函数运算,如UPPER(name) LIKE 'ABC%'就会失效
什么时候该删掉旧索引?
索引不是越多越好。冗余或长期未被使用的索引会拖慢写入性能,并增加优化器决策负担。
- 用
sys.schema_unused_indexes视图(MySQL 5.7+)查哪些索引从没被SELECT使用过;注意它不统计INSERT/UPDATE/DELETE的维护开销 - 检查是否有重复索引:比如已有
(a, b),又建了(a, b, c),前者在大多数场景下是冗余的(除非c经常参与排序或覆盖查询) - 定期用
SHOW INDEX FROM t结合慢查询日志反查,确认每个索引是否真实支撑了高频查询;一个索引三个月内没出现在任何EXPLAIN输出里,大概率可以下线
SELECT object_name AS table_name, index_name, rows_selected, select_latency FROM sys.schema_index_statistics WHERE table_schema = 'your_db' ORDER BY select_latency DESC LIMIT 5;索引设计本质是权衡:它服务于具体查询模式,而非数据本身。很多“优化”失败,是因为盯着单条 SQL 的
EXPLAIN 看,却忽略了业务中查询的分布、并发压力、以及写入频次对索引维护成本的真实影响。









