MySQL 索引入门:从 B+树到最左前缀

举报
神的孩子都在跳舞 发表于 2026/11/04 08:53:30 2026/11/04
【摘要】 第一次在 MySQL 里查一个用户的订单,表只有几十万行,查询却等了好几秒。问题不在数据量,而在查询方式:没有索引,数据库只能从第一行翻到最后一行逐行比对,这就是全表扫描。给关键列加上索引后,同样的查询几乎瞬间完成。一、为什么需要索引把表想象成一本没有目录的书:找某个用户的订单,只能从第一页翻到最后一页,数据翻倍,时间也翻倍。索引就是这本书的目录,按顺序记录关键列的值和对应行的位置。查询时先...

第一次在 MySQL 里查一个用户的订单,表只有几十万行,查询却等了好几秒。问题不在数据量,而在查询方式:没有索引,数据库只能从第一行翻到最后一行逐行比对,这就是全表扫描。给关键列加上索引后,同样的查询几乎瞬间完成。

一、为什么需要索引

把表想象成一本没有目录的书:找某个用户的订单,只能从第一页翻到最后一页,数据翻倍,时间也翻倍。索引就是这本书的目录,按顺序记录关键列的值和对应行的位置。查询时先查目录,定位到少数几行再取数据,扫描量一下子降了下来。目录本身也要占地方、要维护,所以索引能加速查询,却不是免费的。

二、B+树与聚簇、非聚簇索引

InnoDB 的索引大多用 B+树实现:内部节点只保存键值和指针,真实数据都集中在叶子节点,叶子节点按顺序用链表连起来。树很矮,三四层就能存下上亿行;范围查询也很顺,定位到起点后沿着叶子链表往后翻就行。

聚簇索引按主键组织整张表,叶子节点直接保存完整的行数据,一张表只能有一个聚簇索引,通常就是主键。非聚簇索引也叫二级索引,叶子节点保存索引列的值加上主键值,查到主键后还要回到聚簇索引取整行数据,这多走的一步叫回表。

三、创建与查看索引

CREATE INDEX idx_orders_user_id ON orders(user_id);
SHOW INDEX FROM orders;
EXPLAIN SELECT * FROM orders WHERE user_id = 1001;
动手前先用 EXPLAIN 看查询走了哪条路:type 出现 ref 或 range,一般说明用上了索引;出现 ALL,基本就是全表扫描,要检查条件列上有没有合适的索引。

四、联合索引与最左前缀

同时按用户和时间查订单,可以建联合索引:
CREATE INDEX idx_user_created ON orders(user_id, created_at);
它的规则叫最左前缀原则:必须从最左边的列开始依次使用。这个索引能服务 user_id 的查询,也能服务 user_id 加 created_at 的查询,却服务不了只查 created_at 的查询,因为它跳过了最左边的 user_id。设计时把最常出现在 WHERE 里、用来等值匹配的列放在左边。

五、常见的索引失效场景

对索引列做函数运算会失效:WHERE YEAR(created_at) = 2026 要对每一行都算一遍,改成范围条件 WHERE created_at >= '2026-01-01' AND created_at < '2027-01-01' 就能走索引。模糊查询的前导百分号也会失效:WHERE name LIKE '张%' 可以按前缀定位,而 WHERE name LIKE '%张%' 以百分号开头,只能逐行扫描。隐式类型转换同样如此:phone 列是字符串时,WHERE phone = 13812345678 会把整列转成数字再比较,正确写法是给值加引号。

六、一条忠告:索引不是越多越好

每多建一个索引,写入时就要多维护一棵 B+树,插入、更新和删除都会变慢,磁盘占用也会增加。合理的做法是先看慢查询和 EXPLAIN 输出,只给最常用、区分度高的条件建索引,定期清理长期不用的索引。索引是工具,够用、好用才是目标。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。