跨境互联网 跨境互联网
首页
  • AI 工具

    • 绘图提示词工具 (opens new window)
    • ChatGPT 指令 (opens new window)
  • ChatGPT

    • ChatGP T介绍
    • ChatGPT API 中文开发手册
    • ChatGPT 中文调教指南
    • ChatGPT 开源项目
  • Midjourney

    • Midjourney 文档
  • Stable Diffusion

    • Stable Diffusion 文档
  • 其他

    • AIGC 热门文章
    • 账号合租 (opens new window)
    • 有趣的网站
  • Vue

    • Vue3前置
  • JAVA基础

    • Stream
    • Git
    • Maven
    • 常用第三方类库
    • 性能调优工具
    • UML系统建模
    • 领域驱动设计
    • 敏捷开发
    • Java 测试
    • 代码规范及工具
    • Groovy 编程
  • 并发编程&多线程

    • 并发编程
    • 高性能队列 Disruptor
    • 多线程并发在电商系统下的应用
  • 其他

    • 面试题
  • 消息中间中间件

    • Kafka
    • RabbitMQ
    • RocketMQ
  • 任务调度

    • Quartz
    • XXL-Job
    • Elastic-Job
  • 源码解析

    • Mybatis 高级使用
    • Mybatis 源码剖析
    • Mybatis-Plus
    • Spring Data JPA
    • Spring 高级使用
    • Spring 源码剖析
    • SpringBoot 高级使用
    • SpringBoot 源码剖析
    • Jdk 解析
    • Tomcat 架构设计&源码剖析
    • Tomcat Web应用服务器
    • Zookeeper 高级
    • Netty
  • 微服务框架

    • 分布式原理
    • 分布式集群架构场景化解决方案
    • Dubbo 高级使用
    • Dubbo 核心源码剖析
    • Spring Cloud Gateway
    • Nacos 实战应用
    • Sentinel 实战应用
    • Seata 分布式事务
  • 数据结构和算法的深入应用
  • 存储

    • 图和Neo4j
    • MongoDB
    • TiDB
    • MySQL 优化
    • MySQL 平滑扩容实战
    • MySQL 海量数据存储与优化
    • Elasticsearch
  • 缓存

    • Redis
    • Aerospike
    • Guava Cache
    • Tair
  • 文件存储

    • 阿里云 OSS 云存储
    • FastDF 文件存储
  • 基础

    • Linux 使用
    • Nginx 使用与配置
    • OpenResty 使用
    • LVS+Keepalived 高可用部署
    • Jekins
  • 容器技术

    • Docker
    • K8S
    • K8S
  • 01.全链路(APM)
  • 02.电商终极搜索解决方案
  • 03.电商亿级数据库设计
  • 04.大屏实时计算
  • 05.分库分表的深入实战
  • 06.多维系统下单点登录
  • 07.多服务之间分布式事务
  • 08.业务幂等性技术架构体系
  • 09.高并发下的12306优化
  • 10.每秒100W请求的秒杀架构体系
  • 11.集中化日志管理平台的应用
  • 12.数据中台配置中心
  • 13.每天千万级订单的生成背后痛点及技术突破
  • 14.红包雨的架构设计及源码实现
  • 人工智能

    • Python 笔记
    • Python 工具库
    • 人工智能(AI) 笔记
    • 人工智能(AI) 项目笔记
  • 大数据

    • Flink流处理框架
  • 加密区

    • 机器学习(ML) (opens new window)
    • 深度学习(DL) (opens new window)
    • 自然语言处理(NLP) (opens new window)
AI 导航 (opens new window)

Revin

首页
  • AI 工具

    • 绘图提示词工具 (opens new window)
    • ChatGPT 指令 (opens new window)
  • ChatGPT

    • ChatGP T介绍
    • ChatGPT API 中文开发手册
    • ChatGPT 中文调教指南
    • ChatGPT 开源项目
  • Midjourney

    • Midjourney 文档
  • Stable Diffusion

    • Stable Diffusion 文档
  • 其他

    • AIGC 热门文章
    • 账号合租 (opens new window)
    • 有趣的网站
  • Vue

    • Vue3前置
  • JAVA基础

    • Stream
    • Git
    • Maven
    • 常用第三方类库
    • 性能调优工具
    • UML系统建模
    • 领域驱动设计
    • 敏捷开发
    • Java 测试
    • 代码规范及工具
    • Groovy 编程
  • 并发编程&多线程

    • 并发编程
    • 高性能队列 Disruptor
    • 多线程并发在电商系统下的应用
  • 其他

    • 面试题
  • 消息中间中间件

    • Kafka
    • RabbitMQ
    • RocketMQ
  • 任务调度

    • Quartz
    • XXL-Job
    • Elastic-Job
  • 源码解析

    • Mybatis 高级使用
    • Mybatis 源码剖析
    • Mybatis-Plus
    • Spring Data JPA
    • Spring 高级使用
    • Spring 源码剖析
    • SpringBoot 高级使用
    • SpringBoot 源码剖析
    • Jdk 解析
    • Tomcat 架构设计&源码剖析
    • Tomcat Web应用服务器
    • Zookeeper 高级
    • Netty
  • 微服务框架

    • 分布式原理
    • 分布式集群架构场景化解决方案
    • Dubbo 高级使用
    • Dubbo 核心源码剖析
    • Spring Cloud Gateway
    • Nacos 实战应用
    • Sentinel 实战应用
    • Seata 分布式事务
  • 数据结构和算法的深入应用
  • 存储

    • 图和Neo4j
    • MongoDB
    • TiDB
    • MySQL 优化
    • MySQL 平滑扩容实战
    • MySQL 海量数据存储与优化
    • Elasticsearch
  • 缓存

    • Redis
    • Aerospike
    • Guava Cache
    • Tair
  • 文件存储

    • 阿里云 OSS 云存储
    • FastDF 文件存储
  • 基础

    • Linux 使用
    • Nginx 使用与配置
    • OpenResty 使用
    • LVS+Keepalived 高可用部署
    • Jekins
  • 容器技术

    • Docker
    • K8S
    • K8S
  • 01.全链路(APM)
  • 02.电商终极搜索解决方案
  • 03.电商亿级数据库设计
  • 04.大屏实时计算
  • 05.分库分表的深入实战
  • 06.多维系统下单点登录
  • 07.多服务之间分布式事务
  • 08.业务幂等性技术架构体系
  • 09.高并发下的12306优化
  • 10.每秒100W请求的秒杀架构体系
  • 11.集中化日志管理平台的应用
  • 12.数据中台配置中心
  • 13.每天千万级订单的生成背后痛点及技术突破
  • 14.红包雨的架构设计及源码实现
  • 人工智能

    • Python 笔记
    • Python 工具库
    • 人工智能(AI) 笔记
    • 人工智能(AI) 项目笔记
  • 大数据

    • Flink流处理框架
  • 加密区

    • 机器学习(ML) (opens new window)
    • 深度学习(DL) (opens new window)
    • 自然语言处理(NLP) (opens new window)
AI 导航 (opens new window)
  • MySQL优化

    • 1 MySQL架构设计
    • 2 MySQL索引原理&优化
    • 3 性能瓶颈定位MySQL慢查询
    • 4 索引优化整合案例实现
    • 5 索引优化原则&失效情况
    • MySQL海量数据存储与优化

    • 索引优化注意
    • MySQL平滑扩容实战
    • TiDB

    • 图和Neo4j

    • MongoDB

    • 缓存

    • 文件存储

    • Elasticsearch

    • 数据库与缓存
    • MySQL优化
    Revin
    2023-06-17
    目录

    5 索引优化原则&失效情况

    • 创建表 插入数据

      CREATE TABLE users(
        id INT PRIMARY KEY AUTO_INCREMENT,
        user_name VARCHAR(20) NOT NULL COMMENT '姓名',
        user_age INT NOT NULL DEFAULT 0 COMMENT '年龄',
        user_level VARCHAR(20) NOT NULL COMMENT '用户等级',
        reg_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '注册时间'
      );
      
      
      INSERT INTO users(user_name,user_age,user_level,reg_time)
      VALUES('tom',17,'A',NOW()),('jack',18,'B',NOW()),('lucy',18,'C',NOW());
      
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
    • 创建联合索引

      ALTER TABLE users ADD INDEX idx_nal (user_name,user_age,user_level) USING BTREE;
      
      1

    # 1. 全值匹配

    按索引字段顺序匹配使用。

    EXPLAIN SELECT * FROM users WHERE user_name = 'tom';
    
    
    EXPLAIN SELECT * FROM users WHERE user_name = 'tom' AND user_age = 17
    
    
    EXPLAIN SELECT * FROM users WHERE user_name = 'tom' AND user_age = 17 
    AND user_level = 'A';
    
    1
    2
    3
    4
    5
    6
    7
    8

    按顺序使用联合索引时, type类型都是 ref ,使用到了索引 效率比较高

    img

    # 2. 最佳左前缀法则

    如果创建的是联合索引,就要遵循 最佳左前缀法则: 使用索引时,where后面的条件需要从索引的最左前列开始并且不跳过索引中的列使用。

    • 场景1: 按照索引字段顺序使用,三个字段都使用了索引,没有问题。

      EXPLAIN SELECT * FROM users WHERE user_name = 'tom' 
      AND user_age = 17 AND user_level = 'A';
      
      1
      2

      img

    • 场景2: 直接跳过user_name使用索引字段,索引无效,未使用到索引。

      EXPLAIN SELECT * FROM users WHERE user_age = 17 AND user_level = 'A';
      
      1

      img

    • 场景3: 不按照创建联合索引的顺序,使用索引

      EXPLAIN SELECT * FROM users WHERE 
      user_age = 17 AND user_name = 'tom' AND user_level = 'A';
      
      1
      2

      img

      where后面查询条件顺序是 user_age、user_level、user_name与我们建的索引顺序user_name、user_age、user_level不一致,为什么还是使用了索引,这是因为MySql底层优化器给咱们做了优化。

      但是,最好还是要按照顺序 使用索引。

    最佳左前缀底层原理

    ​ MySQL创建联合索引的规则是: 首先会对联合索引最左边的字段进行排序 ( 例子中是 user_name ), 在第一个字段的基础之上 再对第二个字段进行排序 ( 例子中是 user_age )

    ​ 所以: 最佳左前缀原则其实是个B+树的结构有关系, 最左字段肯定是有序的, 第二个字段则是无序的(联合索引的排序方式是: 先按照第一个字段进行排序,如果第一个字段相等再根据第二个字段排序). 所以如果直接使用第二个字段 user_age 通常是使用不到索引的.

    img

    # 3. 不要在索引列上做任何计算

    ​ 不要在索引列上做任何操作,比如计算、使用函数、自动或手动进行类型转换,会导致索引失效,从而使查询转向全表扫描。

    • 插入数据

      INSERT INTO users(user_name,user_age,user_level,reg_time) VALUES('11223344',22,'D',NOW());
      
      1
    • 场景1: 使用系统函数 left()函数

      EXPLAIN SELECT * FROM users WHERE LEFT(user_name, 6) = '112233';
      
      1

      ​ where条件使用计算后的索引字段 user_name,没有使用索引,索引失效。

      img

    • 场景2: 字符串不加单引号 (隐式类型转换)

      EXPLAIN SELECT * FROM users WHERE user_name = 11223344;
      
      1

      img

    注: Extra = Using where 表示Mysql将对storage engine提取的结果进行过滤,过滤条件字段无索引;

    ( 需要回表去查询所需的数据 )

    # 4. 范围之后全失效

    存储引擎不能使用索引中范围条件右边的列

    • 场景1: 条件单独使用user_name时, type=ref, key_len=82

      -- 条件只有一个 user_name
      EXPLAIN SELECT * FROM users WHERE user_name = 'tom';
      
      1
      2

      img

    • 场景2: 条件增加一个 user_age ( 使用常量等值) ,type= ref , key_len = 86

      EXPLAIN SELECT * FROM users WHERE user_name = 'tom' AND user_age = 17;
      
      1

      img

    • 场景3: 使用全值匹配, type = ref , key_len = 168 , 索引都利用上了.

      EXPLAIN SELECT * FROM users WHERE user_name = 'tom' 
      AND user_age = 17 AND user_level = 'A';
      
      1
      2

      img

    • 场景4: 使用范围条件时, avg > 17 , type = range , key_len = 86 , 与场景3 比较,可以发现 user_level 索引没有用上.

      EXPLAIN SELECT * FROM users WHERE user_name = 'tom' 
      AND user_age > 17 AND user_level = 'A';
      
      1
      2

      img

    # 5. 尽量使用覆盖索引

    尽量使用覆盖索引(查询列和索引列尽量一致,通俗说就是对A、B列创建了索引,然后查询中也使用A、B列),减少select *的使用。

    • 场景1: 全值匹配查询, 使用 select *

      EXPLAIN SELECT * FROM users WHERE user_name = 'tom' AND user_age = 17 
      AND user_level = 'A';
      
      1
      2

      img

    • 场景1: 全值匹配查询, 使用 select 字段名1 ,字段名2

      EXPLAIN SELECT user_name , user_age , user_level FROM users WHERE user_name = 'tom' 
      AND user_age = 17 AND user_level = 'A';
      
      1
      2

      使用覆盖索引(查询列与条件列对应),可看到Extra从Null变成了Using index,提高检索效率。

      img

    注: Using index 表示 使用到了索引 , 并且所取的数据完全在索引中就能拿到,

    (使用覆盖索引的时候就会出现)

    # 6. 使用不等于(!=或<>)会使索引失效

    使用 != 会使type=ALL,key=Null,导致全表扫描,并且索引失效。

    • 使用 !=

      EXPLAIN SELECT * FROM users WHERE user_name != 'tom';
      
      1

      img

    # 7. is null 或 is not null也无法使用索引

    在使用is null的时候,索引完全失效,使用is not null的时候,type=ALL全表扫描,key=Null索引失效。

    • 场景1: 使用 is null

      EXPLAIN SELECT * FROM users WHERE user_name IS NULL;
      
      1

      img

    • 场景2: 使用 not null

      EXPLAIN SELECT * FROM users WHERE user_name IS NOT NULL;
      
      1

      img

    # 8. like通配符以%开头会使索引失效

    like查询为范围查询,%出现在左边,则索引失效。%出现在右边索引未失效。口诀:like百分加右边。

    • 场景1

      EXPLAIN SELECT * FROM users WHERE user_name LIKE '%tom%';
      
      1

      img

    • 场景2

      EXPLAIN SELECT * FROM users WHERE user_name LIKE '%tom';
      
      1

      img

    • 场景3

      EXPLAIN SELECT * FROM users WHERE user_name LIKE 'tom%';
      
      1

      img

    注: Using index condition 表示 查找使用了索引,但是需要;';查询数据

    解决%出现在左边索引失效的方法:使用覆盖索引。

    Case1:

    EXPLAIN SELECT user_name FROM users WHERE user_name LIKE '%jack%';
    
    1

    img

    • 对比场景1可以知道, 通过使用覆盖索引 type = index,并且使用了 Using index,从全表扫描变成了全索引扫描.

    注: Useing where; Using index; 查找使用了索引,但是需要的数据都在索引列中能找到,所以不需要回表查询数据

    Case2:

    EXPLAIN SELECT id FROM users WHERE user_name LIKE '%jack%';
    
    1

    img

    • 这里出现 type=index,因为主键自动创建唯一索引。

    Case3:

    EXPLAIN SELECT user_name,user_age FROM users WHERE user_name LIKE '%jack%';
    EXPLAIN SELECT user_name,user_age,user_level FROM users WHERE user_name LIKE '%jack%';
    EXPLAIN SELECT id,user_name,user_age,user_level FROM users WHERE user_name LIKE '%jack%';
    
    1
    2
    3

    img

    • 上面三组, explain执行的结果都相同,表明都使用了索引.

    Case4:

    EXPLAIN SELECT id,user_name,user_age,user_level,reg_time FROM users WHERE user_name 
    LIKE '%jack%';
    
    1
    2

    img

    • 分析:由于只在(user_name,user_age,user_level)上创建索引, 当包含reg_time时,导致结果集偏大(reg_time未建索引)【锅大,锅盖小,不能匹配】,所以type=ALL。

    • like 失效的原理

    img

    1. %号在右: 由于B+树的索引顺序,是按照首字母的大小进行排序,%号在右的匹配又是匹配首字母。所以可以在B+树上进行有序的查找,查找首字母符合要求的数据。所以有些时候可以用到索引.
    2. %号在左: 是匹配字符串尾部的数据,我们上面说了排序规则,尾部的字母是没有顺序的,所以不能按照索引顺序查询,就用不到索引.
    3. 两个%%号: 这个是查询任意位置的字母满足条件即可,只有首字母是进行索引排序的,其他位置的字母都是相对无序的,所以查找任意位置的字母是用不上索引的.

    # 9. 字符串不加单引号导致索引失效

    varchar类型的字段,在查询的时候不加单引号导致索引失效,转向全表扫描。

    • 场景1

      SELECT * FROM users WHERE user_name = '123';
      SELECT * FROM users WHERE user_name = 123;
      
      1
      2

      上述两条sql语句都能查询出相同的数据。

      img

    • 场景2:

      img

      img

      通过explain执行结果可以看出,字符串(name)不加单引号在查询的时候,导致索引失效(type=ref变成了type=ALL,并且key=Null),并全表扫描。

    # 10. 少用or,用or连接会使索引失效

    在使用or连接的时候 type=ALL,key=Null,索引失效,并全表扫描。

    img

    上次更新: 2025/04/03, 11:07:08
    4 索引优化整合案例实现
    1 MySQL架构原理

    ← 4 索引优化整合案例实现 1 MySQL架构原理→

    最近更新
    01
    tailwindcss
    03-26
    02
    PaddleSpeech
    02-18
    03
    whisper
    02-18
    更多文章>
    Theme by Vdoing | Copyright © 2019-2025 跨境互联网 | 豫ICP备14016603号-5 | 豫公网安备41090002410995号
    • 跟随系统
    • 浅色模式
    • 深色模式
    • 阅读模式