本文原创,旨在系统讲解MySQL中B-Tree索引支持的各类查找方式,并结合实际建表、插入数据、执行EXPLAIN计划,全方位理解索引机制的原理和使用边界。本文不含任何虚构内容,适合开发者进阶学习索引调优。
一、前言:什么是B-Tree索引?
在MySQL的InnoDB存储引擎中,默认使用的是B+Tree索引结构。其特点如下:
所有数据都存储在叶子节点中非叶子节点仅存索引键用于导航所有叶子节点之间通过链指针连接,天然支持范围查找
这种结构极大地优化了磁盘IO和范围扫描能力,是MySQL最常见也是最重要的索引形式。
二、索引支持的典型查找类型
1. 全键值查找(Full-Key Match)
SELECT * FROM users WHERE email = 'jack@example.com';
使用email字段的B-Tree索引,进行等值匹配查找效率高,属于O(logN)级别
2. 范围查找(Range Query)
SELECT * FROM users WHERE age BETWEEN 25 AND 30;
如果age字段建立索引,B-Tree通过范围扫描叶子节点即可高效获取结果
3. 前缀匹配(Leftmost Prefix Match)
SELECT * FROM users WHERE name LIKE 'ja%';
LIKE语句为“常量开头”的形式,仍可使用B-Tree索引进行范围查找
4. 多列索引前缀查找
CREATE INDEX idx_name_age_email ON users(name, age, email);
SELECT * FROM users WHERE name = 'jack' AND age = 30;
索引会从最左列开始匹配,只要连续匹配前N列即可使用一旦中间某列为范围查找,后续列将不再使用(范围终止原则)
5. 覆盖索引(Index Only)
SELECT email FROM users WHERE email = 'jack@example.com';
如果查询的字段全部包含在索引中,无需回表,效率最佳
6. LIKE 非前缀查找(无法使用索引)
SELECT * FROM users WHERE name LIKE '%ack';
因为前缀未知,B-Tree索引无法使用,只能全表扫描
7. 函数包裹字段,索引失效
SELECT * FROM users WHERE LOWER(name) = 'jack';
函数包裹字段,MySQL无法使用原始索引
三、建表 + 数据插入 + 索引准备
CREATE TABLE users (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(100),
age INT,
email VARCHAR(100)
);
CREATE INDEX idx_name ON users(name);
CREATE INDEX idx_email ON users(email);
CREATE INDEX idx_name_age_email ON users(name, age, email);
INSERT INTO users (name, age, email) VALUES
('jack', 25, 'jack@example.com'),
('jack', 35, 'jack35@example.com'),
('john', 30, 'john@example.com'),
('jill', 27, 'jill@example.com'),
('jane', 30, 'jane@example.com'),
('jacob', 28, 'jacob@example.com'),
('jim', 25, 'jim@example.com'),
('jack', 40, 'jack40@example.com');
或者插入10万数据
CREATE PROCEDURE insert_users()
BEGIN
DECLARE i INT DEFAULT 1;
WHILE i <= 100000 DO
INSERT INTO users (name, age, email)
VALUES (
CONCAT('ja', LPAD(FLOOR(RAND() * 1000), 3, '0')),
FLOOR(RAND() * 60 + 18),
CONCAT('ja', i, '@example.com')
);
SET i = i + 1;
END WHILE;
END
四、使用EXPLAIN分析各类查询
示例1:全键值查找
EXPLAIN SELECT * FROM users WHERE email = 'jack@example.com';
type: refkey: idx_emailrows: 1Extra: Using where
示例2:范围查找
EXPLAIN SELECT * FROM users WHERE age BETWEEN 25 AND 30;
若无age索引,type为 ALL(全表扫描)建议创建:CREATE INDEX idx_age ON users(age);
示例3:LIKE前缀查找
EXPLAIN SELECT * FROM users WHERE name LIKE 'ja%';
type: rangekey: idx_namerows: N
示例4:LIKE非前缀查找
EXPLAIN SELECT * FROM users WHERE name LIKE '%ack';
type: ALLkey: NULL(未使用索引)
示例5:多列索引前缀匹配
EXPLAIN SELECT * FROM users WHERE name = 'jack';
key: idx_namepossible_keys: idx_name, idx_name_age_email
示例6:多列 + 范围终止
EXPLAIN SELECT * FROM users WHERE name = 'jack' AND age > 30 AND email = 'jack40@example.com';
possible_keys: idx_name, idx_email, idx_name_age_emailkey: idx_email解释:联合索引 (name, age, email) 中,name = 命中第一列,age > 是范围查询,触发范围终止,后面的 email 无法继续使用索引;优化器因此判断使用 idx_email(单列索引)效率更高
联合索引范围终止示意图:
(name, age, email) 联合索引使用顺序:
name = ? ✅
↓
age > ? ✅(范围)
↓——(⚠️ 截断,email失效)
email = ? ❌(无法使用)
示例7:覆盖索引
EXPLAIN SELECT email FROM users WHERE email = 'jack@example.com';
Extra: Using index(表示覆盖索引)
示例8:函数导致索引失效
EXPLAIN SELECT * FROM users WHERE LOWER(name) = 'jack';
key: NULLtype: ALL
五、EXPLAIN关键字段讲解
字段名含义id查询语句编号(子查询分层)select_type查询类型(SIMPLE、SUBQUERY等)table当前访问的表名type连接类型(越靠左越优)possible_keys可能使用的索引列表key实际使用的索引名key_len索引字段长度(越短越好)ref索引列与哪个常量/字段比较rows预计扫描的行数Extra附加信息(是否使用临时表、排序等)type取值优劣排名(从优到劣):
system` > `const` > `eq_ref` > `ref` > `range` > `index` > `ALL
Extra重要取值含义:
Using index:表示覆盖索引,无需回表 ✅Using where:使用了索引,但仍需进一步筛选条件Using filesort:使用外部排序 ❌Using temporary:使用了临时表 ❌
六、总结与实践建议
查询方式是否用索引说明email = 'xx'✅等值查找,效率高age BETWEEN 25 AND 30✅(需索引)范围查找name LIKE 'ja%'✅前缀匹配name LIKE '%ack'❌无法使用索引name = 'jack' AND age > 30✅(部分)范围终止LOWER(name) = 'jack'❌函数导致索引失效SELECT email FROM ...✅覆盖索引,极高性能
📌 建议
使用EXPLAIN配合每一条关键查询,验证是否用到索引为频繁查询条件建适合的联合索引,遵循“最左前缀”原则使用LIKE时尽量避免'%xxx'的形式减少在WHERE中使用函数、表达式包裹字段合理利用覆盖索引提升性能
📚 官方参考资料
MySQL EXPLAIN语法及输出详解
官方文档,详细介绍了 EXPLAIN 的字段含义及执行计划的解读方法。
https://dev.mysql.com/doc/refman/8.0/en/explain-output.html
MySQL 索引优化与使用指南
包含索引的类型、优化原则以及查询优化技术。
https://dev.mysql.com/doc/refman/8.0/en/mysql-indexes.html
MySQL 索引使用限制和范围终止规则
讲解联合索引的最左前缀规则和范围查询导致索引使用截断的细节。
https://dev.mysql.com/doc/refman/8.0/en/multiple-column-indexes.html#multiple-column-indexes-prefixes
如果你觉得这篇索引查找与EXPLAIN实战指南对你有帮助,欢迎点赞、转发或收藏。