一、索引是什么?能干嘛?
类比理解:索引就像书的目录。比如你想查《哈利波特》中 “伏地魔” 出现的页数,不用逐页翻书,直接看目录找关键词就行。数据库里的索引就是帮你快速找到数据的 “目录”。
核心作用:
- 提速查询:把 “全表扫描”(逐行找数据)变成 “精准定位”,查询速度从 “翻完整本书” 变成 “查目录找页码”。
- 约束数据:比如主键索引能保证数据不重复(像身份证号唯一)。
- 加速排序:索引本身是有序的,排序时不用临时整理数据。
二、索引的 4 种主要类型(附通俗例子)
1. btree 索引(最常用的 “万能索引”)
- 原理:像字典的拼音目录,按顺序排列(如 a-b-c...),支持范围查询(如查 “年龄> 18”)和精准查询。
适用场景:90% 的场景都能用,比如:
create index idx_age on users(age); -- 给年龄字段建索引
- 类比:查字典时,知道 “张三” 的拼音,直接按字母顺序翻到对应页。
2. hash 索引(“快速匹配器”)
- 原理:把数据变成 “哈希值”(类似快递单号),查数据时直接 “对单号”,速度极快(o (1))。
- 限制:只能精准匹配(如
where id=1
),不能查范围(如id>100
),且仅内存表(memory 引擎)可用。 - 类比:快递柜取件,输入单号直接开门,无法 “找所有单号大于 100 的快递”。
3. 全文索引(“文本搜索神器”)
- 原理:专门针对文章、评论等长文本,把关键词拆分成 “词条” 存储(类似搜索引擎的关键词索引)。
- 适用场景:查 “包含‘mysql’的文章”,用
match against
语句:
create fulltext index idx_article on articles(content);
- 注意:mysql 5.7 + 优化后性能更好,别用 like '% 关键词 %'(太慢)。
4. 空间索引(“地图专用索引”)
- 原理:存储地理坐标(如经纬度),支持 “查找附近 5 公里的咖啡店” 这类查询。
- 适用场景:外卖 app 找附近商家、地图软件标地点。
- 限制:字段必须是 geometry 类型(如点、线、面),innodb 引擎从 5.7 开始支持。
三、啥时候该建索引?啥时候别建?
✅ 建议建索引的情况:
- 经常用来查询的字段:比如
where name='张三'
中的 name 字段。 - 表关联字段:多表 join 时的关联字段(如订单表的 user_id 关联用户表)。
- 唯一性字段:主键(id)、邮箱(唯一不重复)。
- 频繁排序的字段:如
order by create_time
,索引自带顺序,不用额外排序。
❌ 不建议建索引的情况:
- 数据重复率高的字段:比如 “性别”(只有男 / 女),建索引还不如直接全表扫描快。
- 频繁更新的字段:比如 “在线状态”,每次修改都要更新索引,影响性能。
- 小表数据:表只有 100 行数据,全表扫描比查索引更快(索引本身也占空间)。
- 不参与查询的字段:建了索引也用不上,纯属浪费空间。
四、复合索引:多个字段 “组队” 加速查询
1. 什么是复合索引?
- 给多个字段一起建索引,比如
(name, age)
,相当于 “组合目录”。 - 语法:
create index idx_name_age on users(name, age);
2. 最左前缀原则(必须掌握!)
- 规则:查询条件必须从左到右使用索引中的字段,不能跳过。
- 示例:索引是
(name, age)
,支持:
where name='张三' and age=18; -- 正确,用全索引 where name='张三'; -- 正确,用name部分
不支持:
where age=18; -- 错误,跳过了name,索引失效 where name='张三' and age=18 and address='北京'; -- 正确,address不影响,前两个字段用上索引
- 类比:索引像 “省 - 市 - 区” 的地址,你必须先指定 “省”,才能用索引快速定位,直接查 “区” 无法用索引。
五、索引优化:让查询飞起来的技巧
1. 覆盖索引:“不回表” 的高效查询
- 定义:查询的所有字段都在索引里,不用再回表查数据(类似查目录时直接拿到所有需要的信息,不用翻书)。
- 示例:
-- 表结构:users(id, name, age) create index idx_name_age on users(name, age); -- 索引包含name和age select name, age from users where name='张三'; -- 直接从索引取数据,不用回表
2. 索引失效场景(避坑指南)
- 用了函数或表达式:
where upper(name)='zhangsan'; -- 对name做了大写转换,索引失效
类型不匹配:
where id='123'; -- id是数字类型,传字符串可能导致索引失效
模糊查询以通配符开头:
where name like '%张三'; -- 无法用索引(不知道从哪开始查)
or 条件分隔无关联字段:
where id=1 or name='张三'; -- 若id和name没有共同索引,可能失效
3. 索引管理命令(常用)
创建索引:
create index idx_name on users(name); -- 普通索引 create unique index idx_email on users(email); -- 唯一索引
删除索引:
drop index idx_name on users;
查看索引:
show index from users;
分析查询是否用索引:
explain select * from users where name='张三'; -- 看执行计划中的key列
六、不同引擎的索引差异(简单了解)
引擎 | 支持的索引类型 | 特点 |
---|---|---|
innodb | btree、全文、空间 | 数据和索引存一起(聚簇索引),适合事务 |
myisam | btree、全文、rtree | 索引和数据分开存,不支持事务 |
memory | hash、btree | 数据在内存,查询极快,但重启数据丢失 |
七、实战案例:电商订单表索引优化
场景:
查询 “近 30 天内,已支付(status=2)且金额> 1000 的订单”,按时间倒序。
表结构:
create table orders ( id bigint primary key, user_id bigint, order_time datetime, status tinyint, amount decimal(10,2) );
优化方案:
创建联合覆盖索引:
create index idx_status_time_amount on orders(status, order_time, amount);
查询语句:
select id, user_id, amount from orders where status=2 and order_time >= now() - interval 30 day and amount > 1000 order by order_time desc;
优化原理:
- 联合索引
(status, order_time, amount)
满足最左前缀原则,先按状态筛选,再按时间和金额过滤。 order_time
在索引中是有序的,查询时直接按倒序取,不用额外排序。- 查询字段
id, user_id, amount
都在索引中(id
是主键,默认在索引里),实现覆盖索引,不回表。
八、索引使用的核心原则(必记!)
- 少而精:单表索引不超过 5 个,避免过度索引(每个索引都增加写入开销)。
- 联合索引优先:多个字段频繁一起查询时,建联合索引比多个单列索引更高效。
- 覆盖索引优先:让查询字段尽量在索引中,减少 “回表” 操作。
- 定期维护:用
analyze table
更新索引统计信息,用explain
分析慢查询是否用了索引。 - 避免坑点:不用函数处理字段、不写
select *
(只查需要的字段)、模糊查询用like '关键词%'
(别以通配符开头)。
通过合理设计索引,mysql 查询性能能提升 10-100 倍!但记住:索引不是越多越好,要在 “查询速度” 和 “写入速度” 之间找平衡哦~
到此这篇关于一文掌握mysql 数据库索引详解的文章就介绍到这了,更多相关mysql数据库索引内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
发表评论