WHERE条件中使用函数导致索引失效,因MySQL无法将函数结果与B+树中原始字段值对齐;应改写为范围查询、建生成列索引或避免字段运算。

为什么 WHERE 条件里用了函数,索引就失效了
MySQL 无法对表达式结果直接使用 B+ 树索引做快速查找,比如 WHERE YEAR(create_time) = 2023 或 WHERE UPPER(name) = 'ABC'。优化器看到的是函数计算后的值,而索引里存的是原始字段值,二者无法对齐。
实操建议:
- 改写为范围查询:用
create_time BETWEEN '2023-01-01' AND '2023-12-31 23:59:59'替代YEAR() - 建生成列 + 索引(MySQL 5.7+):
ALTER TABLE orders ADD COLUMN create_year INT AS (YEAR(create_time)) STORED;
CREATE INDEX idx_create_year ON orders(create_year); - 避免在索引字段上做任何运算、类型转换或函数调用
ORDER BY 和 GROUP BY 怎么用好联合索引
MySQL 的联合索引遵循最左前缀原则,但排序和分组还额外依赖“索引有序性”。如果 ORDER BY a, b,而索引是 (a, c, b),那 b 就无法利用索引排序——因为中间插了 c,破坏了 a,b 的物理连续顺序。
实操建议:
- 让
ORDER BY字段尽量靠前且连续出现在联合索引中,例如INDEX(a, b, c)支持ORDER BY a, b,但不支持ORDER BY b, c -
GROUP BY同理,且若含聚合函数(如COUNT()),确保分组字段能走索引,否则会触发Using temporary; Using filesort - 如果既要
WHERE a = ?又要ORDER BY b,优先建INDEX(a, b),而不是分开建两个单列索引
什么时候该删掉重复或低效的索引
重复索引指功能完全被另一个索引覆盖,比如已有 INDEX(a, b),又建了 INDEX(a);低效索引指长期没被 SELECT 使用、却在 INSERT/UPDATE/DELETE 中持续拖慢写性能的索引。
IEStore是一款B2C独立网上商店系统,适合企业及个人快速构建个性化网上商店。系统是基于PHP语言及MYSQL数据库构架开发的跨平台开源程序。IEStore网上商店系统不仅在产品功能、稳定性、安全性和SEO支持(搜索引擎优化)等方面具有在同类产品领先地位,重要的是在功能架构上、操作上符合国际化标准,成为国际化电子商务的最佳软件选择之一。功能概要国际化标准IEStore网上商店系统是一个带有多国
实操建议:
- 查冗余索引:
SELECT * FROM sys.schema_redundant_indexes;
(需启用sysschema) - 看索引实际使用率:
SELECT index_name, rows_selected FROM sys.schema_index_statistics WHERE table_name = 'orders';
- 删除前确认:没有
WHERE b = ?单独查询(否则INDEX(a, b)不能替代INDEX(b)) - 高频写入表中,超过 5 个索引就要警惕——每个索引都会增加 B+ 树维护成本
LIKE '%xxx' 真的完全不能走索引吗
以通配符开头的模糊查询(LIKE '%abc')确实无法使用 B+ 树索引的有序结构,但不是所有模糊场景都无解。
实操建议:
- 后缀匹配可走索引:
LIKE 'abc%'能用INDEX(name),前提是没加函数或隐式转换 - 全文索引(
FULLTEXT)适合长文本关键词搜索,但只支持MyISAM和InnoDB(5.6+),且对短词( - 倒排表或外部搜索引擎(如 Elasticsearch)更适合复杂模糊、拼音、错别字等需求——MySQL 原生不擅长这个
- 业务上可考虑前置约束:比如先用精确字段过滤(
status = 'active'),再对小结果集做LIKE '%xxx'
索引优化最常被忽略的一点:它不是静态配置,而是随查询模式和数据分布动态变化的。上线后必须定期看 slow_log 和 sys.statement_analysis,而不是只靠建表时的预判。









