索引是数据库中对数据位置的快速映射,本质是有序数据结构(如B+树),存储字段值及对应主键或行指针;用于加速WHERE、ORDER BY、JOIN等操作,需遵循最左前缀原则,避免低选择性字段和过度创建。
索引不是数据本身,而是对数据位置的快速映射——就像书本末尾的索引页,查“B树”不用翻遍全书,直接跳到第42页。MySQL 中,INDEX 本质是一棵有序的数据结构(多数是 B+ 树),存储的是字段值 + 对应的主键或行指针。
没索引时,SELECT * FROM users WHERE name = 'Alice' 可能触发全表扫描;加了 INDEX(name) 后,引擎能直接定位匹配行,I/O 次数大幅下降。
以下情况不建索引,性能容易掉坑里:
WHERE 条件中高频出现的列,尤其是选择性高(重复值少)的字段,比如 user_id、email
ORDER BY created_at DESC —— 如果经常按时间倒序查最新10条,INDEX(created_at) 能避免文件排序(Using filesort)JOIN 的关联字段,如 orders.user_id 关联 users.id,两边都建议有索引,否则驱动表小也扛不住被扫十几万次LIKE 'abc%' 可走索引,但 LIKE '%abc' 或 LIKE '%abc%' 基本失效(除非用全文索引)INDEX(a, b, c) 实际上等价于三个索引:(a)、(a,b)、(a,b,c),但不包含 (b) 或 (b,c)。这意味着:
WHERE a = 1 AND b = 2 ✅ 走索引WHERE a = 1 ORDER BY c ✅ 可能用上索引做排序(覆盖 a,c)WHERE b = 2 ❌ 不走索引(跳过了最左列 a)WHERE status = ? AND created_at > ?,把区分度高的放前面更稳,比如 INDEX(status, created_at) 比反过来更有效每多一个索引,INSERT/UPDATE/DELETE 都要同步更新 B+ 树,写放大明显。更隐蔽的问题包括:
VARCHAR(255) 直接 INDEX(content),MySQL 默认取前 767 字节(utf8mb4 下约 191 字符),可能截断导致索引失效UPDATE 的字段建索引,会引发大量页分裂和碎片,SHOW INDEX FROM tbl 查看 Cardinality 是否严重偏低gender 只有 'M'/'F')建普通索引意义很小,优化器大概率直接放弃使用真正难的不是建索引,是判断哪些查询值得索引、哪些该用覆盖索引、哪些其实该改 SQL 或加缓存——执行计划(EXPLAIN)里那几行 type 和 key 才是关键线索。