索引是数据库的“目录页”,能大幅提升查询效率,但需根据查询条件和执行计划合理创建,避免滥用导致写入性能下降和优化器误判。
MySQL 默认不给任何字段建索引——就像一本没目录的 1000 页书,你要找“事务隔离级别”这个词,只能一页页翻。建了索引,相当于提前把关键词按
顺序整理好,再附上对应页码(即数据行位置),SELECT 时直接跳转,省掉全表扫描(type: ALL)的 IO 开销。实际中,10 万行以上的表,一个没索引的 WHERE user_id = 12345 可能要扫几万行;加了索引后,通常只需 3–4 次磁盘 IO 就定位到数据。
建索引不是凭感觉,而是看 EXPLAIN 输出里哪些列反复出现在 WHERE、ORDER BY、GROUP BY 或 JOIN 条件中。常见有效场景包括:
WHERE status = 'active' —— 但前提是该字段区分度高(比如 90% 是 active 就别建)ORDER BY created_at DESC LIMIT 20 —— 索引能避免排序临时表JOIN orders ON users.id = orders.user_id —— 关联字段必须有索引,否则驱动表每扫一行,被驱动表都全表扫一遍WHERE category = 'book' AND price BETWEEN 20 AND 50 —— 考虑建联合索引 (category, price),注意最左前缀原则索引不是建了就自动生效。MySQL 优化器会权衡成本,遇到以下情况,常直接放弃索引,退化为全表扫描:
WHERE YEAR(create_time) = 2025 → 改成 WHERE create_time >= '2025-01-01' AND create_time
user_id 是 VARCHAR,却写 WHERE user_id = 12345 → MySQL 自动转成数字比较,索引失效WHERE name LIKE '%john' → B+Tree 无法从左边开始匹配,LIKE 'john%' 才能用索引WHERE a = 1 OR b = 2,若只有 a 有索引,整个条件大概率不用索引WHERE score * 2 > 100 → 改成 WHERE score > 50
每次 INSERT、UPDATE、DELETE 都要同步更新所有相关索引树,尤其在高并发写入场景下,索引越多,写延迟越明显,甚至引发锁竞争。同时:
VARCHAR(255) 字段建索引,可能比原数据还大INNODB 表只能有一个;其他都是二级索引,查完还要回表取完整行真正该建索引的地方,是那些被高频查询、且过滤性足够强的字段——不是所有 WHERE 都值得加,更不是所有字段都适合单独建索引。联合索引的设计、字段顺序、是否覆盖查询,才是进阶关键。