【MySQL11】进阶篇 | 索引_#3使用规则

目录

  1. 验证索引执行效率
  2. 联合索引|最左前缀法则
  3. 全部索引失效常见原因
  4. or、null、数据分布引发的索引失效
  5. SQL 索引提示(use /ignore/force index)
  6. 覆盖索引、回表原理
  7. 前缀索引使用教程
  8. 单列索引 vs 联合索引对比
  9. 索引创建全套设计原则

一、验证索引效率

无索引状态

sql

sql 复制代码
select *from tb_sku where sn = '1000000003124'

没有索引会进行全表扫描,查询速度很慢。

创建 B + 树单列索引

sql

sql 复制代码
create index idx_sku_sn on tb_sku(sn);

建立索引之后查询会走 B + 树索引检索,大幅提速。

MySQL 普通索引底层结构为 B+‑Tree


二、联合索引核心:最左前缀法则

多字段联合索引,查询必须匹配索引最左侧前列,不能跳过索引字段;跳过后面字段,跳过位置之后索引失效

示例联合索引顺序:(profession,age,status)

  1. 正常命中全部索引

sql

sql 复制代码
explain select *from tb_user where profession = '软件工程' and age = 31 and status = '0';
  1. 命中前两列索引

sql

sql 复制代码
explain select *from tb_user where profession = '软件工程' and age = 31;
  1. 跳过最左首字段 → 索引直接失效,type=ALL 全表扫描

sql

sql 复制代码
explain select *from tb_user where age = 31 and status = '0';
  1. 跳过中间 age 字段 → age 之后 status 索引失效,仅 profession 生效

sql

sql 复制代码
explain select *from tb_user where profession = '软件工程' and status = '0';
  1. where 条件字段顺序不影响,MySQL 优化器会自动调整顺序,满足最左前缀即可生效

sql

sql 复制代码
explain select *from tb_user where age = 31 and status = '0' and profession = '软件工程'

范围查询陷阱

联合索引遇到 < > 范围条件,范围右侧所有字段索引直接失效

sql

sql 复制代码
-- age>30 是范围查询,status索引失效
select *from tb_user where profession= '软件工程' and age > 30 and status = '0'

优化方案: 优先使用 >= <= 等值边界代替大于小于范围,尽量把范围字段放在联合索引最后一位。


三、高频索引失效场景

1. 在索引列上做运算、函数、隐式类型转换

sql

sql 复制代码
-- phone为字符串索引字段,不加单引号发生隐式转换,索引失效
explain select *from tb_user where phone = 17799999015;

索引字段必须保持原生类型,不要运算、不要调用函数、不要类型转换

2. like 模糊查询

  • like 'xxx%':尾部通配,索引生效
  • like '%xxx'like '%xxx%':头部带通配符,索引失效全表扫描

3. or 连接条件,一侧无索引则整条 SQL 索引失效

sql

sql 复制代码
-- id带索引、age没有索引,or导致索引失效
explain select *from tb_user where id = 10 or age = 23;

解决办法:给 or 后面 age 字段新建索引。

4. 字段 is null /is not null

sql

sql 复制代码
-- 有概率命中索引
select *from tb_user where profession is null

-- 大概率索引失效,全表扫描 type=all
select *from tb_user where profession is not null

5. MySQL 优化器判断全表扫描更快,主动放弃索引

当查询条件匹配表中绝大多数的数据,索引查找成本高于全表扫描,MySQL 自动放弃索引。

sql

sql 复制代码
-- 绝大多数phone满足该条件,触发全表扫描
explain select *from tb_user where phone >= '1973892485'

四、SQL 提示:手动控制 MySQL 选用索引

适合一张表存在多条索引,MySQL 优化器选错索引时手动干预

sql

sql 复制代码
-- 创建单列索引
create index idx_user_pro on tb_user(profession);

-- 1.use index:建议MySQL使用指定索引
select *from tb_user use index(idx_user_pro) where profession = '软件工程';

-- 2.ignore index:忽略指定索引
select *from tb_user ignore index(idx_user_pro) where profession = '软件工程';

-- 3.force index:强制使用该索引
select *from tb_user force index(idx_user_pro) where profession = '软件工程';

五、覆盖索引 & 回表查询

基础原理

  1. 聚集索引(主键索引):B + 树叶子节点存放该行全部字段数据
  2. 辅助索引(普通索引):叶子节点只存放主键 id

回表:通过普通索引拿到主键 id 之后,再去主键索引读取整行数据,多出一次 IO 查询。

覆盖索引定义

查询所需要的全部字段,都存在于联合索引当中,不需要回表读取主键索引 执行计划 Extra 字段出现 Using index = 命中覆盖索引,性能最高 Using index condition = 使用索引检索,但是需要回表查询数据

案例

联合索引 (profession,age,status)

sql

sql 复制代码
-- select * 需要回表
explain select *from tb_user where profession = '软件工程' and age = 31 and status = '0'

-- 查询字段全部包含在索引内,触发覆盖索引,Using‑index
explain select id, profession from tb_user where profession = '软件工程' and age = 31 and status = '0'

避坑准则:禁止习惯性写 select *,极易触发回表,拖慢查询速度

SQL 优化例题

现有字段 id, username, password, status

sql

sql 复制代码
select id, username, password from tb_user where username = 'itcast';

优化方案:建立联合索引 idx_username_up(username,password),触发覆盖索引,免去回表。


六、前缀索引

适用场景

varchar、text 等超长字符串字段,完整建立索引占用磁盘 IO 大、索引体积臃肿。 只存储字段前面一部分字符当作索引,节省索引存储空间。

创建语法

sql

sql 复制代码
-- 取该字段前n位作为索引
create index idx_xxxx on table_name(column(n));

索引选择性(核心参数)

选择性 = 不重复数值 ÷ 表总记录数;数值越接近 1,索引效果越好,唯一索引选择性 = 1

sql

sql 复制代码
-- 完整字段选择性
select count(distinct email) / count(*) from tb_user;

-- 截取前10位前缀选择性
select count(distinct substring(email, 1, 10))/count(*) from tb_user;

调试不同截取长度,在存储空间与选择性之间取平衡点。


七、单列索引 vs 联合索引

单列索引

一个索引只包含单个字段

sql

sql 复制代码
-- phone单列索引,查询phone+name条件,命中phone索引之后必须回表查找name
select *from tb_user where phone = '1779999991110' and name = '韩信'

联合索引

sql

sql 复制代码
create index idx_user_phone_name on tb_user(phone, name)

查询条件 phone + name,索引已经携带两个字段,能够触发覆盖索引、跳过回表查询。

开发规范:优先建立合适顺序的联合索引,减少大量单列索引;遵循最左前缀规划索引字段顺序,等值字段放前面、范围查询字段放在索引末尾。


八、完整索引创建设计原则

  1. 数据表数据量大的时候才建立索引,小表没必要;
  2. 经常用于 where 查询、join 连接、order by、group by 的字段建立索引;
  3. 区分度高的字段建立索引,优先创建唯一索引;
  4. 长字符串 varchar/text 字段,采用前缀索引节约磁盘;
  5. 优先设计联合索引,利用覆盖索引避免回表 IO;
  6. 一张表索引数量需要管控,索引过多会拖慢 insert/update/delete 写入速度;
  7. 索引字段设置 NOT NULL,NULL 会造成索引失效、查询优化困难。
相关推荐
名字还没想好☜1 小时前
Go 的 sync.Cond 实战:用条件变量做等待/通知,比忙轮询省 CPU
开发语言·数据库·后端·golang·go
wWYy.2 小时前
Mysql:有哪些锁?
数据库·mysql
李可以量化2 小时前
Tornado 从了解到精通(一)下:异步与非阻塞 IO 核心原理
java·数据库·tornado
starzhang2 小时前
05 从 Perfetto 看懂 Binder 调用链
性能优化
hey_sml2 小时前
MySQL常用操作速记:从字符集到游标全解析
java·开发语言·mysql
云技纵横2 小时前
线上接口突然超时,怎么判断卡在 Nginx、线程池、连接池还是 SQL?
后端·sql·mysql
VALENIAN瓦伦尼安教学设备2 小时前
ASHOOTER激光对中仪如何通过颜色确定调整是否合适
数据库·嵌入式硬件·算法
Wang's Blog2 小时前
AI Agent白手起家58: 项目可观测性——用 LangSmith 实现全链路追踪
数据库·人工智能
大龄秃头程序员3 小时前
一次关于 LRUCache 的工程化落地:从数据结构到 Feed 图片缓存实践
性能优化