索引能提速多少?看场景,不是所有查询都受益
索引不是“一加就快”,它的收益高度依赖查询模式和数据分布。在理想情况下(如高基数字段上的等值查询),
WHERE user_id = 12345从全表扫描(O(n))降到 B+ 树查找(O(log n)),百万行表可能从 800ms 降到 5ms —— 提速百倍。但低基数列(如
status ENUM('active','inactive'),只有两个值)上建索引,优化器大概率直接忽略它,因为走索引还要回表,不如全表扫得干脆。MySQL 通常在列唯一值占比低于约 30% 时放弃使用该索引。
复合索引怎么排顺序?最左前缀不是玄学
复合索引
INDEX idx_name_phone (name, phone)能命中
WHERE name = 'Alice'和
WHERE name = 'Alice' AND phone = '138xxxx',但对
WHERE phone = '138xxxx'完全无效——这就是“最左前缀原则”。顺序决定覆盖能力: 把选择性高的列(如
user_id)放前面,比把低选择性列(如
gender)放前面更有效; 如果常查
WHERE category = ? AND created_at > ? ORDER BY created_at DESC,那
(category, created_at)比
(created_at, category)更合适,因为范围查询后的列无法用于索引排序; 避免冗余:已有
(a, b, c),再建
(a, b)就是浪费空间和写开销。
为什么 EXPLAIN 显示“Using index”却还是慢?
Using index表示用了覆盖索引(Covering Index),即查询所需所有字段都在索引里,不用回表——这本该很快。但如果出现慢,常见原因有: 索引本身太宽:比如在
VARCHAR(1000)字段上建了前缀长度为 255 的索引,单个索引项变大,B+ 树层级加深,IO 次数上升; 大量重复值导致索引页内扫描行数多(例如
WHERE status IN ('pending','processing') 匹配几十万行,即使覆盖索引也要遍历这么多索引记录);
查询返回结果集过大,网络传输或客户端处理成了瓶颈,而非索引本身问题。
哪些操作会让索引彻底失效?
不是写了 WHERE 就能用索引。这些写法会让 MySQL 直接放弃走索引:
对索引列用函数:WHERE YEAR(create_time) = 2025→ 改成
WHERE create_time >= '2025-01-01' AND create_time ;隐式类型转换:
WHERE mobile = 13812345678(mobile 是
VARCHAR)→ 数字会被转字符串,但部分版本不走索引,统一用引号写成
'13812345678'; LIKE 左模糊:
WHERE name LIKE '%abc'无法利用 B+ 树有序性;右模糊
'abc%'可以; OR 连接非索引列:
WHERE indexed_col = 1 OR non_indexed_col = 2,整条条件大概率退化为全表扫描。
真正难的从来不是“建不建索引”,而是理解你的查询在引擎内部走了哪条路径——
EXPLAIN看懂了,90% 的索引问题就定位了一半。
