为什么 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;<br>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中持续拖慢写性能的索引。
实操建议:
查冗余索引: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,而不是只靠建表时的预判。
