索引是mysql查询加速的底层b+tree数据结构,决定select性能;需命中条件才生效,b-tree支持等值/范围/排序查询,hash仅支持等值,fulltext专用于全文检索;加索引须依explain分析,避免冗余,注意联合索引字段顺序。

索引就是数据库的“目录”,不是附加功能,而是查询加速的底层数据结构
索引在MySQL里不是锦上添花的配置项,而是直接决定SELECT快慢的核心机制。它本质是一棵B+Tree(InnoDB默认),存储的是「字段值 + 对应行的物理位置」,而不是复制整行数据。没有索引时,MySQL只能全表扫描——比如查100万行里的某条记录,平均要读50万行;加了索引后,通常3~4次磁盘IO就能定位,性能差上百倍。关键点在于:索引生效的前提是查询条件能命中索引结构,否则它就只是白占空间、拖慢INSERT/UPDATE/DELETE。
B-Tree索引为什么是主力?Hash和全文索引哪些场景不能用
InnoDB只支持B-Tree索引(实际是B+Tree变种),因为它能同时支撑等值查询、范围查询(>、BETWEEN)、排序(ORDER BY)和最左前缀匹配。而Hash索引仅Memory引擎原生支持,且只响应完整等值查询(WHERE col = ?),不支持col > 100或WHERE col1 = ? AND col2 > ?;FULLTEXT索引专用于MATCH() AGAINST()全文检索,但对中文需额外分词插件(MySQL原生不支持),且无法用于WHERE col LIKE '%xx%'这类模糊查询。
- 别在
datetime字段上建Hash索引——语法会通过,但InnoDB会静默转成B-Tree -
FULLTEXT必须建在CHAR/VARCHAR/TEXT列上,且建表时指定ENGINE=InnoDB(5.6.4+) - 联合索引
(a,b,c)对WHERE a=1 AND b>10有效,但对WHERE b>10完全无效
什么时候加索引?看执行计划比猜更可靠
别凭感觉加索引。先用EXPLAIN看查询是否走了索引:EXPLAIN SELECT * FROM orders WHERE user_id = 123;。重点看type字段——const/ref表示高效命中,range尚可,ALL就是全表扫描。再检查key列是否显示用了哪个索引,rows是否远小于表总行数。常见误判点:
- 单列索引
user_id和联合索引(user_id, status)共存时,优化器可能选错,用FORCE INDEX临时干预 -
OR条件容易让索引失效,比如WHERE a=1 OR b=2,建议拆成UNION或补上复合索引 -
LIKE以通配符开头(LIKE '%abc')必然无法用B-Tree索引,这是结构限制,不是配置问题
索引不是越多越好:维护成本和写放大必须算进账
每多一个索引,INSERT就要多写一棵B+Tree叶子节点,UPDATE改索引列时还要分裂页、合并页。线上表如果QPS高、写入频繁,盲目加索引反而导致innodb_row_lock_waits飙升。真实案例:某订单表加了5个冗余索引后,日均慢查没降,但磁盘IO等待从2ms涨到18ms。建议做法:
- 用
information_schema.STATISTICS定期查未被使用的索引:SELECT * FROM STATISTICS WHERE TABLE_SCHEMA='db' AND INDEX_NAME NOT IN (SELECT DISTINCT INDEX_NAME FROM performance_schema.events_statements_summary_by_digest WHERE DIGEST_TEXT LIKE '%table%'); - 删除索引前先在测试环境开
slow_query_log并设long_query_time=0,跑一周业务流量,确认无慢查回归 - 联合索引优先覆盖高频查询组合,宁可少建两个单列索引,也不要建三个互相重叠的联合索引
最常被忽略的一点:索引字段顺序直接影响过滤效率。比如用户登录常用WHERE email = ? AND status = 'active',那(email, status)比(status, email)高效得多——因为status的区分度通常远低于email,放前面会导致B+Tree第一层就过滤不掉多少数据。










