禅与计算机 禅与计算机
首页
  • Java基础

    • 聊一聊java一些核心知识点
    • 聊聊java面向对象核心知识点
    • 聊聊Java中的异常
    • 聊聊Java中的常用类String
    • 万字长文带你细聊Java注解本质
    • 来聊聊Java的反射机制
    • 深入解析Java泛型的魅力与机制
    • Java集合框架深度解析与面试指南
    • Java常用集合类HashMap深度解析
    • LinkedHashMap源码到面试题的全解析
    • 深入解析CopyOnWriteArrayList的工作机制
    • Java基础IO总结
    • Java三大IO模型小结
    • Java BIO NIO AIO详解
    • Java进阶NIO之IO多路复用详解
    • Java8流式编程入门
    • 一文速通lambda与函数式编程
    • Java8函数式方法引用最佳实践
  • Java并发编程

    • Java并发编程基础小结
    • 深入理解Java中的final关键字
    • 浅谈Java并发安全发布技术
    • 浅谈Java并发编程中断的哲学
    • Java线程池知识点小结
    • 浅谈Java线程池中拒绝策略与流控的艺术
    • synchronized关键字使用指南
    • 深入源码解析synchronized关键字
    • 详解JUC包下的锁
    • 详解并发编程中的CAS原子类
    • LongAdder源码分析
    • AQS源码解析
    • 深入剖析Java并发编程中的死锁问题
    • Java并发容器总结
    • 详解Java并发编程volatile关键字
    • 并发编程ThreadLocal必知必会
    • CompletableFuture基础实践小结
    • CompletableFuture异步多任务最佳实践
    • 硬核详解FutureTask设计与实现
    • 线程池大小设置的底层逻辑与场景化方案
    • 来聊一个有趣的限流器RateLimiter
  • JVM相关

    • 从零开始掌握 JVM
    • JVM核心知识点小结
    • JVM指令集概览:基础与应用
    • JVM类加载器深度解析
    • JVM方法区深度解析
    • Java内存模型JMM详解
    • Java对象大小的精确计算方法
    • 逃逸分析在Java中的应用与优化
    • 从零开始理解JVM的JIT编译机制
    • G1垃圾回收器:原理详解与调优指南
    • JVM故障排查实战指南
    • JVM内存问题排错最佳实践
    • JVM内存溢出排查指南
    • 简明的Arthas使用教程
    • 简明的Arthas配置及基础运维教程
    • 基于Arthas Idea的JVM故障排查与指令生成
    • 基于arthas量化监控诊断java应用方法论与实践
    • 深入剖析arthas技术原理
  • 深入理解Spring框架

    • Spring 核心知识点全面解析
    • Spring核心功能IOC详解
    • Spring AOP 深度剖析与实践
    • Spring 三级缓存机制深度解析
    • 深入 Spring 源码,剖析设计模式的落地实践
    • 探索 Spring 事务的奥秘
    • 深入解析Spring Bean的生命周期管理
    • 解读 Spring Boot 核心知识点
    • Spring Boot 启动优化实战:1分钟到13秒的排查与优化之路
    • Spring Boot自动装配原理及实践
    • 一文快速上手Sharding-JDBC
    • sharding-jdbc如何实现分页查询
    • 基于DynamicDataSource整合分库分表框架Shardingsphere
  • 计算机组成原理

    • 计算机硬件知识小结
    • CPU核心知识点小结
    • 浅谈CPU流水线的艺术
    • 从Java程序员视角聊聊CPU缓存
    • CPU任务调度和伪共享问题小结
    • CPU MESI缓存一致性协议
    • CPU内存管理机制
    • 内存深度解析
    • 磁盘存储原理
    • 详解计算机启动步骤
    • CPU南北桥架构与发展史
    • CPU中断机制与硬件交互详解
  • 操作系统

    • 如何实现一个高性能服务器
    • Linux文件结构与文件权限
    • Linux常见压缩指令小结
    • Linux核心系统调用详解
    • Linux进程管理
    • Linux线程管理
    • 进程与线程深度解析
    • Linux进程间通信机制
    • 零拷贝技术原理与实践
    • CPU缓存一致性问题深度解析
    • IO任务与CPU调度艺术
  • 计算机网络

    • 网卡通信原理详解
    • 网卡数据包处理指南
    • 基于抓包详解TCP协议
  • 编码最佳实践

    • 浅谈现代软件工程TDD最佳实践
    • 浅谈TDD模式下并发程序设计与实现
    • 面向AI编程新范式Trae后端开发环境搭建与实践
    • 基于提示词工程的Redis签到功能开发实践
    • 基于Vibe Coding的Redis分页查询实现
    • 告别AI无效对话:资深工程师的提示词设计最佳实践
  • 实用技巧与配置

    • Mac常用快捷键与效率插件指南
    • Keynote技术科普短视频制作全攻略
  • 写作

    • 写好技术博客的5大核心原则:从认知科学到AI工具的全流程指南
  • 开发工具

    • IDEA配置详解与高效使用指南
  • Nodejs
  • 博客搭建
  • Redis

    • Redis核心知识小结
    • 解锁Redis发布订阅模式
    • 掌握Redis事务
    • Redis主从复制技术
    • Redis的哨兵模式详解
    • 深度剖析Redisson分布式锁
    • 详解redis单线程设计思路
    • 来聊聊Redis所实现的Reactor模型
    • Redis RDB持久化源码深度解析
    • 来聊聊redis的AOF写入
    • 来聊聊Redis持久化AOF管道通信的设计
    • 来聊聊redis集群数据迁移
    • Redis SDS动态字符串深度解析
    • 高效索引的秘密:redis跳表设计与实现
    • 聊聊redis中的字典设计与实现
  • MySQL

    • MySQL基础知识点小结
    • 解读MySQL 索引基础
    • MySQL 索引进阶指南
    • 解读MySQL Explain关键字
    • 探秘 MySQL 锁:原理与实践
    • 详解MySQL重做日志redolog
    • 详解undoLog在MySQL MVCC中的运用
    • MySQL二进制日志binlog核心知识点
    • MySQL高效插入数据的最佳实践
    • MySQL分页查询优化指南
    • MySQL流式查询的奥秘与应用解析
    • 来聊聊分库分表
    • 来聊聊大厂常用的分布式ID生成方案
  • ElasticSearch

    • 从Lucene到Elasticsearch:进化之路
    • ES 基础使用指南
    • ElasticSearch如何写入一篇文档
    • 深入剖析Elasticsearch文档读取原理
    • 聊聊ElasticSearch性能调优
    • Spring借助Easy-Es操作ES
  • Netty

    • 一文快速了解高性能网络通信框架Netty
    • Netty网络传输简记
    • 来聊聊Netty的ByteBuf
    • 来聊聊Netty消息发送的那些事
    • 解密Netty高性能之谜:NioEventLoop线程池阻塞分析
    • 详解Netty中的责任链Pipeline如何管理ChannelHandler
    • Netty Reactor模型常见知识点小结
    • Netty如何驾驭TCP流式传输?粘包拆包问题全解
    • Netty解码器源码解析
  • 消息队列

    • 一文快速入门消息队列
    • 消息队列RocketMQ入门指南
    • 基于RocketMQ实现分布式事务
    • RocketMQ容器化最佳实践
    • RocketMQ常见问题与深度解析
    • Kafka快速安装与使用指南
  • Nginx

    • Linux下的nginx安装
    • Nginx基础入门总结
    • Nginx核心指令小结
    • Nginx进程结构与核心模块初探
    • Nginx应用进阶HTTP核心模块配置
    • Nginx缓存及HTTPS配置小记
    • nginx高可用实践简记
    • Nginx性能优化
  • 微服务基础

    • 微服务基础知识小结
    • 分布式事务核心概念小结
    • OpenFeign核心知识小结
    • 微服务组件Gateway核心使用小结
    • 分布式事务Seata实践
    • 用 Docker Compose 完成 Seata 的整合部署
  • Nacos

    • Nacos服务注册原理全解析
    • Nacos服务订阅流程全解析
    • Nacos服务变更推送流程全解析
    • 深入解析SpringCloud负载均衡器Loadbalancer
    • Nacos源码环境搭建与调试指南
  • Seata

    • 深度剖析Seata源码
  • Docker部署

    • 一文快速掌握docker的理念和基本使用
    • 使用docker编排容器
    • 基于docker-compose部署微服务基本环境
    • 基于docker容器化部署微服务
    • Gateway全局异常处理及请求响应监控
    • Docker图形化界面工具Portainer最佳实践
  • Go基础

    • 一文带你速通Go语言基础语法
    • 一文快速掌握Go语言切片
    • 来聊聊go语言的hashMap
    • 一文速通go语言类型系统
    • 浅谈Go语言中的面向对象
    • go语言是如何实现协程的
    • 聊聊go语言中的GMP模型
    • 极简的go语言channel入门
    • 聊聊go语言基于epoll的网络并发实现
    • 写给Java开发的Go语言协程实践
  • mini-redis实战

    • 来聊聊我用go手写redis这件事
    • mini-redis如何解析处理客户端请求
    • 实现mini-redis字符串操作
    • 硬核复刻redis底层双向链表核心实现
    • 动手复刻redis之go语言下的字典的设计与落地
    • Go 语言下的 Redis 跳表设计与实现
    • Go 语言版 Redis 有序集合指令复刻探索
  • 项目编排

    • Spring脚手架创建简记
    • Spring脚手架集成分页插件
    • Spring脚手架集成校验框架
    • maven父子模块两种搭建方式简记
    • SpringBoot+Vue3前后端快速整合入门
    • 来聊聊Java项目分层规范
  • 场景设计

    • Java实现文件分片上传
    • 基于时间缓存优化浏览器轮询阻塞问题
    • 基于EasyExcel实现高效导出
    • 10亿数据高效插入MySQL最佳方案
    • 从开源框架中学习那些实用的位运算技巧
  • CI/CD

    • 基于NETAPP实现内网穿透
    • 基于Gitee实现Jenkins自动化部署SpringBoot项目
    • Jenkins离线安装部署教程简记
    • 基于Nexus搭建Maven私服基础入门
    • 基于内网的Jenkins整合gitlab综合方案简记
  • 监控方法论

    • SpringBoot集成Prometheus与Grafana监控
    • Java监控度量Micrometer全解析
    • 从 micrometer计量器角度快速上手promQL
    • 硬核安利一个监控告警开源项目Nightingale
  • Spring AI

    • Spring AI Alibaba深度实战:一文掌握智能体开发全流程
    • Spring AI Alibaba实战:JVM监控诊断Arthas Agent的工程化构建与最佳实践
  • 大模型评测

    • M2.7 真能打!我用两个真实场景测了测,结果有点意外
    • Qoder JetBrains插件评测:祖传代码重构与接口优化实战
关于
收藏
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

sharkchili

计算机禅修者
首页
  • Java基础

    • 聊一聊java一些核心知识点
    • 聊聊java面向对象核心知识点
    • 聊聊Java中的异常
    • 聊聊Java中的常用类String
    • 万字长文带你细聊Java注解本质
    • 来聊聊Java的反射机制
    • 深入解析Java泛型的魅力与机制
    • Java集合框架深度解析与面试指南
    • Java常用集合类HashMap深度解析
    • LinkedHashMap源码到面试题的全解析
    • 深入解析CopyOnWriteArrayList的工作机制
    • Java基础IO总结
    • Java三大IO模型小结
    • Java BIO NIO AIO详解
    • Java进阶NIO之IO多路复用详解
    • Java8流式编程入门
    • 一文速通lambda与函数式编程
    • Java8函数式方法引用最佳实践
  • Java并发编程

    • Java并发编程基础小结
    • 深入理解Java中的final关键字
    • 浅谈Java并发安全发布技术
    • 浅谈Java并发编程中断的哲学
    • Java线程池知识点小结
    • 浅谈Java线程池中拒绝策略与流控的艺术
    • synchronized关键字使用指南
    • 深入源码解析synchronized关键字
    • 详解JUC包下的锁
    • 详解并发编程中的CAS原子类
    • LongAdder源码分析
    • AQS源码解析
    • 深入剖析Java并发编程中的死锁问题
    • Java并发容器总结
    • 详解Java并发编程volatile关键字
    • 并发编程ThreadLocal必知必会
    • CompletableFuture基础实践小结
    • CompletableFuture异步多任务最佳实践
    • 硬核详解FutureTask设计与实现
    • 线程池大小设置的底层逻辑与场景化方案
    • 来聊一个有趣的限流器RateLimiter
  • JVM相关

    • 从零开始掌握 JVM
    • JVM核心知识点小结
    • JVM指令集概览:基础与应用
    • JVM类加载器深度解析
    • JVM方法区深度解析
    • Java内存模型JMM详解
    • Java对象大小的精确计算方法
    • 逃逸分析在Java中的应用与优化
    • 从零开始理解JVM的JIT编译机制
    • G1垃圾回收器:原理详解与调优指南
    • JVM故障排查实战指南
    • JVM内存问题排错最佳实践
    • JVM内存溢出排查指南
    • 简明的Arthas使用教程
    • 简明的Arthas配置及基础运维教程
    • 基于Arthas Idea的JVM故障排查与指令生成
    • 基于arthas量化监控诊断java应用方法论与实践
    • 深入剖析arthas技术原理
  • 深入理解Spring框架

    • Spring 核心知识点全面解析
    • Spring核心功能IOC详解
    • Spring AOP 深度剖析与实践
    • Spring 三级缓存机制深度解析
    • 深入 Spring 源码,剖析设计模式的落地实践
    • 探索 Spring 事务的奥秘
    • 深入解析Spring Bean的生命周期管理
    • 解读 Spring Boot 核心知识点
    • Spring Boot 启动优化实战:1分钟到13秒的排查与优化之路
    • Spring Boot自动装配原理及实践
    • 一文快速上手Sharding-JDBC
    • sharding-jdbc如何实现分页查询
    • 基于DynamicDataSource整合分库分表框架Shardingsphere
  • 计算机组成原理

    • 计算机硬件知识小结
    • CPU核心知识点小结
    • 浅谈CPU流水线的艺术
    • 从Java程序员视角聊聊CPU缓存
    • CPU任务调度和伪共享问题小结
    • CPU MESI缓存一致性协议
    • CPU内存管理机制
    • 内存深度解析
    • 磁盘存储原理
    • 详解计算机启动步骤
    • CPU南北桥架构与发展史
    • CPU中断机制与硬件交互详解
  • 操作系统

    • 如何实现一个高性能服务器
    • Linux文件结构与文件权限
    • Linux常见压缩指令小结
    • Linux核心系统调用详解
    • Linux进程管理
    • Linux线程管理
    • 进程与线程深度解析
    • Linux进程间通信机制
    • 零拷贝技术原理与实践
    • CPU缓存一致性问题深度解析
    • IO任务与CPU调度艺术
  • 计算机网络

    • 网卡通信原理详解
    • 网卡数据包处理指南
    • 基于抓包详解TCP协议
  • 编码最佳实践

    • 浅谈现代软件工程TDD最佳实践
    • 浅谈TDD模式下并发程序设计与实现
    • 面向AI编程新范式Trae后端开发环境搭建与实践
    • 基于提示词工程的Redis签到功能开发实践
    • 基于Vibe Coding的Redis分页查询实现
    • 告别AI无效对话:资深工程师的提示词设计最佳实践
  • 实用技巧与配置

    • Mac常用快捷键与效率插件指南
    • Keynote技术科普短视频制作全攻略
  • 写作

    • 写好技术博客的5大核心原则:从认知科学到AI工具的全流程指南
  • 开发工具

    • IDEA配置详解与高效使用指南
  • Nodejs
  • 博客搭建
  • Redis

    • Redis核心知识小结
    • 解锁Redis发布订阅模式
    • 掌握Redis事务
    • Redis主从复制技术
    • Redis的哨兵模式详解
    • 深度剖析Redisson分布式锁
    • 详解redis单线程设计思路
    • 来聊聊Redis所实现的Reactor模型
    • Redis RDB持久化源码深度解析
    • 来聊聊redis的AOF写入
    • 来聊聊Redis持久化AOF管道通信的设计
    • 来聊聊redis集群数据迁移
    • Redis SDS动态字符串深度解析
    • 高效索引的秘密:redis跳表设计与实现
    • 聊聊redis中的字典设计与实现
  • MySQL

    • MySQL基础知识点小结
    • 解读MySQL 索引基础
    • MySQL 索引进阶指南
    • 解读MySQL Explain关键字
    • 探秘 MySQL 锁:原理与实践
    • 详解MySQL重做日志redolog
    • 详解undoLog在MySQL MVCC中的运用
    • MySQL二进制日志binlog核心知识点
    • MySQL高效插入数据的最佳实践
    • MySQL分页查询优化指南
    • MySQL流式查询的奥秘与应用解析
    • 来聊聊分库分表
    • 来聊聊大厂常用的分布式ID生成方案
  • ElasticSearch

    • 从Lucene到Elasticsearch:进化之路
    • ES 基础使用指南
    • ElasticSearch如何写入一篇文档
    • 深入剖析Elasticsearch文档读取原理
    • 聊聊ElasticSearch性能调优
    • Spring借助Easy-Es操作ES
  • Netty

    • 一文快速了解高性能网络通信框架Netty
    • Netty网络传输简记
    • 来聊聊Netty的ByteBuf
    • 来聊聊Netty消息发送的那些事
    • 解密Netty高性能之谜:NioEventLoop线程池阻塞分析
    • 详解Netty中的责任链Pipeline如何管理ChannelHandler
    • Netty Reactor模型常见知识点小结
    • Netty如何驾驭TCP流式传输?粘包拆包问题全解
    • Netty解码器源码解析
  • 消息队列

    • 一文快速入门消息队列
    • 消息队列RocketMQ入门指南
    • 基于RocketMQ实现分布式事务
    • RocketMQ容器化最佳实践
    • RocketMQ常见问题与深度解析
    • Kafka快速安装与使用指南
  • Nginx

    • Linux下的nginx安装
    • Nginx基础入门总结
    • Nginx核心指令小结
    • Nginx进程结构与核心模块初探
    • Nginx应用进阶HTTP核心模块配置
    • Nginx缓存及HTTPS配置小记
    • nginx高可用实践简记
    • Nginx性能优化
  • 微服务基础

    • 微服务基础知识小结
    • 分布式事务核心概念小结
    • OpenFeign核心知识小结
    • 微服务组件Gateway核心使用小结
    • 分布式事务Seata实践
    • 用 Docker Compose 完成 Seata 的整合部署
  • Nacos

    • Nacos服务注册原理全解析
    • Nacos服务订阅流程全解析
    • Nacos服务变更推送流程全解析
    • 深入解析SpringCloud负载均衡器Loadbalancer
    • Nacos源码环境搭建与调试指南
  • Seata

    • 深度剖析Seata源码
  • Docker部署

    • 一文快速掌握docker的理念和基本使用
    • 使用docker编排容器
    • 基于docker-compose部署微服务基本环境
    • 基于docker容器化部署微服务
    • Gateway全局异常处理及请求响应监控
    • Docker图形化界面工具Portainer最佳实践
  • Go基础

    • 一文带你速通Go语言基础语法
    • 一文快速掌握Go语言切片
    • 来聊聊go语言的hashMap
    • 一文速通go语言类型系统
    • 浅谈Go语言中的面向对象
    • go语言是如何实现协程的
    • 聊聊go语言中的GMP模型
    • 极简的go语言channel入门
    • 聊聊go语言基于epoll的网络并发实现
    • 写给Java开发的Go语言协程实践
  • mini-redis实战

    • 来聊聊我用go手写redis这件事
    • mini-redis如何解析处理客户端请求
    • 实现mini-redis字符串操作
    • 硬核复刻redis底层双向链表核心实现
    • 动手复刻redis之go语言下的字典的设计与落地
    • Go 语言下的 Redis 跳表设计与实现
    • Go 语言版 Redis 有序集合指令复刻探索
  • 项目编排

    • Spring脚手架创建简记
    • Spring脚手架集成分页插件
    • Spring脚手架集成校验框架
    • maven父子模块两种搭建方式简记
    • SpringBoot+Vue3前后端快速整合入门
    • 来聊聊Java项目分层规范
  • 场景设计

    • Java实现文件分片上传
    • 基于时间缓存优化浏览器轮询阻塞问题
    • 基于EasyExcel实现高效导出
    • 10亿数据高效插入MySQL最佳方案
    • 从开源框架中学习那些实用的位运算技巧
  • CI/CD

    • 基于NETAPP实现内网穿透
    • 基于Gitee实现Jenkins自动化部署SpringBoot项目
    • Jenkins离线安装部署教程简记
    • 基于Nexus搭建Maven私服基础入门
    • 基于内网的Jenkins整合gitlab综合方案简记
  • 监控方法论

    • SpringBoot集成Prometheus与Grafana监控
    • Java监控度量Micrometer全解析
    • 从 micrometer计量器角度快速上手promQL
    • 硬核安利一个监控告警开源项目Nightingale
  • Spring AI

    • Spring AI Alibaba深度实战:一文掌握智能体开发全流程
    • Spring AI Alibaba实战:JVM监控诊断Arthas Agent的工程化构建与最佳实践
  • 大模型评测

    • M2.7 真能打!我用两个真实场景测了测,结果有点意外
    • Qoder JetBrains插件评测:祖传代码重构与接口优化实战
关于
收藏
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • Redis

  • MySQL

    • MySQL基础知识点小结
    • Linux环境下MySQL部署安装
    • 解读MySQL 索引基础
    • MySQL 索引进阶指南:深入探秘关键知识点
    • 解读MySQL Explain关键字:优化查询执行计划的实用指南
      • 写在文章开头
      • 详解explain对应关键字
        • id字段(执行计划唯一标识)
        • table字段(执行计划针对的数据表)
        • select_type(SQL语句查询类型)
        • type字段(重点,SQL查询访问方法)
        • extra(SQL语句额外信息)
        • possible_keys(可能用到的索引信息)
        • key(用到的索引名称)
        • key_len(使用索引时,对应的索引长度)
        • ref(与索引匹配时,比对条件的类型)
        • rows(数据扫描体量评估)
        • filter(读取和过滤占比)
      • 小结
      • 参考
    • 深入剖析 MySQL 某条执行过程
    • 探秘 MySQL 锁:原理与实践
    • 聊一个MySQL插入死锁问题
    • 详解MySQL重做日志redolog
    • 详解undoLog在MySQL多版本并发控制MVCC中的运用
    • MySQL二进制日志binlog核心知识点小结
    • MySQL高效插入数据的最佳实践
    • 提升 MySQL 批量更新效率的底层原理与优化策略
    • MySQL分页查询优化指南
    • MySQL LEFT JOIN 性能优化策略
    • MySQL流式查询的奥秘与应用解析
    • 主键自增是否会降低数据库insert性能
    • 内网环境MySQL操作非正常耗时问题排查小结
    • 来聊聊分库分表
    • 来聊聊大厂常用的分布式ID生成方案
    • 仿MyBatis-Plus实现跨数据源事务
  • ElasticSearch

  • StarRocks

  • 数据库
  • MySQL
sharkchili
2025-01-24
目录

解读MySQL Explain关键字:优化查询执行计划的实用指南

# 写在文章开头

在MySQL数据库中,优化查询性能是每个开发人员和数据库管理员都需要面对的重要挑战之一。其中,EXPLAIN关键字是一个强大的工具,可以帮助我们深入了解MySQL是如何执行查询的,以及如何优化查询性能。

本文将深入探讨MySQL中的EXPLAIN关键字,探究其背后的工作原理和输出信息含义。通过本文的阐述,您将了解如何解读EXPLAIN的输出结果,优化查询执行计划,提升数据库性能,以及避免常见的查询性能陷阱。

无论您是初学者还是有经验的数据库专家,本文都将为您提供有价值的见解和实用的技巧,助您在MySQL数据库中更好地利用EXPLAIN关键字,优化查询性能,提升数据库应用的效率和稳定性。

Hi,我是 sharkChili ,是个不断在硬核技术上作死的技术人,是 CSDN的博客专家 ,也是开源项目 Java Guide 的维护者之一,熟悉 Java 也会一点 Go ,偶尔也会在 C源码 边缘徘徊。写过很多有意思的技术博客,也还在研究并输出技术的路上,希望我的文章对你有帮助,非常欢迎你关注我的公众号: 写代码的SharkChili 。

同时也非常欢迎你star我的开源项目mini-redis:https://github.com/shark-ctrl/mini-redis (opens new window)

因为近期收到很多读者的私信,所以也专门创建了一个交流群,感兴趣的读者可以通过上方的公众号获取笔者的联系方式完成好友添加,点击备注 “加群” 即可和笔者和笔者的朋友们进行深入交流。

# 详解explain对应关键字

通过explain关键字可以获取我们给定查询SQL经由成本和规则优化后的执行计划,通过这个计划我们可以得到查询语句实际的工作步骤,这里我们就针对这关键字得出的执行计划的每一列都进行介绍。

为了更直观的演示explain各个关键字段的信息,我们这里不妨通过两张表针对每一种访问方式进行讲解,对应数据表的DDL如下所示,可以看到笔者基于MySQL8.0创建了一张s1表,其中:

  1. id作为主键。
  2. key1作为普通索引。
  3. key2是唯一索引。
  4. key_part1+key_part2+key_part3构成唯一索引。

s2与s1结构一致,这里就不多做介绍,对应DDL语句如下所示:

CREATE TABLE s1
(
    id           INT NOT NULL AUTO_INCREMENT,
    key1         VARCHAR(100),
    key2         INT,
    key3         VARCHAR(100),
    key_part1    VARCHAR(100),
    key_part2    VARCHAR(100),
    key_part3    VARCHAR(100),
    common_field VARCHAR(100),
    PRIMARY KEY (id),
    KEY          idx_key1 (key1),
    UNIQUE KEY idx_key2 (key2),
    KEY          idx_key3 (key3),
    KEY          idx_key_part(key_part1,key_part2,key_part3)
) Engine = InnoDB CHARSET = utf8;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

注意,笔者一直强调MySQL的版本为8.0,所以后续的执行计划都是基于MySQL8.0版本展开探讨的,读者在基于笔者文章进行实践是需要注意保持版本一致性。

# id字段(执行计划唯一标识)

针对每一个select语句都会为其分配一个id字段,该id就代表的每一个select语句的执行计划信息。

我们先说个简单的例子,针对下面这句单表执行的语句,它就只有一行数据,所以就只有一个id为1的执行计划:

explain select * FROM  s1 WHERE s1.common_field =1;
1

我们再来一个union合并查询:

explain select * FROM  s1 union select * from s2;
1

从执行计划可以看到s1的id为1,s2的id为2,分别进行了一个select查询:

需要注意的是连接查询的驱动表和被驱动表的id都是一样的,出现在前面的是驱动表,而后面的就是被驱动表:

explain select * from s1 inner join s2 on s1.id =s2.id ;

1
2

从执行计划就可以看出,s1就是驱动表,s2就是被驱动表:

我们再来一个特殊的SQL,这句原本是子查询,正常情况下应该是s1表的id为1,s2表的id为2:

explain select * FROM s1  where key1 in (select key3 from s2 );
1

但是SQL优化器经过分析发现这句可以被优化为连接查询,即下面这句SQL:

explain select * from s1 inner join s2 on s1.key1 =s2.key3 ;
1

所以执行计划就显示id是一样的,且s1作为驱动表,s2作为被驱动表:

# table字段(执行计划针对的数据表)

table字段含义比较简单,它表示当前查询计划所针对的数据表,例如下面这个简单查询语句:

explain select * FROM  s1 WHERE s1.common_field =1;
1

它所查询的就是针对s1表:

而下面这句涉及连接查询,所以从执行计划中也能看出不同执行计划所针对的表:

explain select * from s1 inner join s2;
1

可以看到驱动表s1进行全表扫描,而被驱动表s2是通过hash join进行连接查询:

# select_type(SQL语句查询类型)

select_type决定了你的SQL涉及的查询类型,常见的有:

  1. SIMPLE:简单查询,如下所示,可以看到简单的SQL语句就属于这种查询类型
explain select * from s1
1

对应的执行计划如下所示:

  1. PRIMARY:涉及关联或者子查询的语句对应左边的语句就是PRIMARY,如下SQL所示,可以看到对应的u表的查询就可以作为PRIMARY语句:
explain select * FROM  s1 union select * from s2;
1

我们查看执行计划的截图,可以看到涉及这种嵌套查询的SQL左边的SQL就是PRIMARY:

  1. UNION:从执行计划的截图就可以看出union关键字后面的SQL就属于union
explain select * FROM  s1 union select * from s2;

1
2

对应执行计划如下图所示:

  1. UNION RESULT:包含union的处理结果集,在union和union all语句中,基于其它查询结果进行合并(可能有去重的过程),需要通过一个临时表才能完成的操作就是UNION RESULT也就是我们上述那句SQL的第三步。
  2. DEPENDENT SUBQUERY:如下SQL所示,在SQL优化器明确指明子查询无法转为半连接查询的情况下,第一个select的子查询对应的select type就是DEPENDENT SUBQUERY:
explain select * from s1 where s1.common_field in (SELECT id from s2 WHERE s1.common_field=s2.common_field) or key3='a';
1

对应的执行计划如下所示,可以看到s2的执行类型就是DEPENDENT SUBQUERY:

  1. DEPENDENT UNION:如下SQL所示,在涉及union的子查询中有无数个小查询,除去union的左边哪个小查询,其余的都是DEPENDENT UNION
explain select * from s1 WHERE key1 IN (SELECT key1 from s1 union SELECT key1 from s2)
1

这一点,从执行计划中就可以看出,子查询内部的s2查询的类型就是DEPENDENT UNION

  1. DERIVED:在FROM列表中包含的子查询被标记为DERIVED(衍生);MySQL会递归执行这些子查询, 把结果放在临时表里:
explain SELECT * from (select COUNT(*)  from student as a) b
1

对应的我们可以在执行计划中印证这一点:

# type字段(重点,SQL查询访问方法)

type决定了进行SQL查询的时的访问方法,该字段对于SQL执行性能分析有着至关重要的参考价值:

  1. system:表中只有一行或者空表,即存储引擎中统计的数据是正确的。
  2. const:基于聚簇索引或者非空的唯一二级索进行定位数据,时间复杂度为O(1),这种高速的常量级查询我们就可以称为const:
explain select * FROM  s1 WHERE id=1;
1

对应执行计划如下:

  1. eq_ref:该查询意味着进行关联查询时,被驱动表内部走了聚簇索引或者非空的二级索引查询:
explain SELECT * FROM s1 inner join  s2 on s1.id=s2.id;
1
  1. ref:通过那些非唯一的二级索引进行精准定位,这种在二级索引区间构成一个扫描区间进行定位,然后再通过回表获取所有数据的执行就是ref:
explain select * from s1 WHERE  key1='a';
1

对应的执行计划截图如下图所示:

  1. fulltext:全文匹配,大字符索引匹配。
  2. ref_or_null:基于普通二级索引查询且查询时还需要查询可能为空的情况:
explain select * from s1 WHERE  key1='a' or key1 is NULL ;
1
  1. unique_subquery:即子查询被优化为exist,且子查询返回的是聚簇索引:
explain select * from s1 where s1.common_field in (SELECT id from s2 WHERE s1.common_field=s2.common_field) or key3='a';
1
  1. index_subquery:和上述查询类似,只不过子查询内部返回的是普通二级索引:

  2. range:范围查询。

  3. index_merge:索引合并,即进行SQL查询时对应的条件都是索引类型,SQL优化器进行查询时让两个索引分别到自己的二级索引树拿到有序的id集合然后取交集得到聚簇索引值进行回表:

对应的SQL如下,可以看到我们查询条件都走了索引,查询结果是基于多个索引的扫描区间共同构成的聚簇索引,然后取并集进行回表:

EXPLAIN select * FROM s1 WHERE KEY1='a' or key3='b'
1

这一点我们可以通过查询执行计划印证:

  1. index:进行SQL查询时,基于二级索引全扫描但无需回表的访问方法就是index,这里我们给出一个比较特殊的例子,可以看到这条SQL查询条件是key_part2(即联合索引由key_part1、key_part2、key_part3构成的联合索引),虽然不符合最左匹配原则,但是在MySQL8.0版所提供的Index Skip Scan即索引跳跃这一特性的支持下,这条SQL的执行计划也是显示走index的:
explain select s1.key_part1,s1.key_part2,s1.key_part3 from s1 WHERE  key_part2='a';
1

对应执行计划如下图所示:

这里我们也简单补充一下索引跳越的工作机制,以我们上述的SQL为例,其底层本质工作过程为:

  1. 基于联合索引获取所有key_part1的值X、Y、Z。
  2. 基于前导结果构建出类似于where (key_part1=X and key_part2='a') or (key_part1=Y and key_part2='a') or (key_part1=Z and key_part2='a') 的查询SQL利用最左匹配原则走联合索引进行结果查询并合并:

  1. ALL:全表扫描,这种方式就不做强调了,当查询语句没有用到索引亦或者MySQL优化器认为索引无法有效、高效过滤数据时,就会执行全表扫描,该方式执行流程也非常简单,它会直接扫描数据所有数据页的数据加载到内存结合我们给定的条件进行过滤聚合,从而得出需要的结果。

对应的我们也给出全表扫描对应的SQL示例,即查询时使用没有创建索引的字段common_field:

explain SELECT * FROM s1 WHERE common_field='1';
1

对应的执行计划如下所示:

# extra(SQL语句额外信息)

这个字段也很重要,它表示当前SQL语句的一些额外的信息:

  1. Using filesort:即代表SQL查询时用到了文件扫描,使用了外部的索引进行排序,并没有用到我们自己定义的索引,性能较差。
  2. using index:这种方式性能就不错了,使用了索引并且不需要回表就得到了我们需要的数据,即用到了索引覆盖。
  3. Using temporary:MySQL查询排序时使用了临时表性能较于filesort更差。
  4. using where:即代表查询时仅仅用到了普通的where条件,并没有用到任何索引,查询需要在server层进行判断。
  5. Using join buffer:在进行连接查询时,被驱动表的数据定位并没有走索引,于是将驱动表的数据放入缓冲区进行关联匹配。
  6. impossible where:说明where条件基本得不到需要的结果,筛选数据时一直处于false的状态。

# possible_keys(可能用到的索引信息)

表示当前查询可能用到的索引。如下这个执行计划,它就以为着可能用到了主键

# key(用到的索引名称)

表示用到的索引名称,如下所示下面这条sql可能就用到了这两个索引。

# key_len(使用索引时,对应的索引长度)

key_len表示使用索引时,对应使用到的索引的长度,在MySQL的EXPLAIN语句中,key_len列表示使用索引的键部分的字节数。它是一个估计值,根据查询中使用的索引类型和数据类型来计算。通常,key_len越小,性能就越好,因为它意味着需要读取更少的数据块。 例如,如果你有一个使用VARCHAR(100)数据类型的列作为索引,并且查询中只使用了前10个字符作为搜索条件,则key_len将是10。如果你使用的是INT(10)数据类型的列作为索引,则key_len将是4,因为INT类型占用4个字节。 在优化查询时,理解key_len可以帮助你确定哪些索引可以更有效地支持查询,以及如何进一步优化索引设计。

例如下面这一句,实际上索引长度就是303,原因很简单:

  1. key1为varchar(100)且用的是utf8,所以长度为300字节。
  2. 允许空再加一个字节。
  3. varchar需要2字节维护长度进行再加2字节。 最终得到303字节:
explain select * from s1 WHERE key1>'a' and key1<'b';
1

# ref(与索引匹配时,比对条件的类型)

表示进行索引匹配时,与之比对的数据类型,例如下面这句key1比对的是一个函数计算值,所以ref是func:

explain select * FROM s1 inner join s2 on s2.key1 =UPPER(s1.key1);
1

例如这句与索引匹配的是常数,所以得到的是const:

explain select * from s1 WHERE  key1='a';
1

当然进行关联查询时被驱动表得到的就是驱动表的id,如下返回的就是s1.id:

explain SELECT * FROM s1 inner join  s2 on s1.id=s2.id;
1

# rows(数据扫描体量评估)

rows意味着我们查询时大体需要扫描多少行,对于单表查询没什么,但是对于多表查询,从这个数据我们可以得知关联查询哪个作为驱动表:

explain SELECT * FROM customer c inner join customer_balances cb on c.id =cb.c_id ;
1

因为cb的rows为1,可知这张表变为被驱动表走索引定位:

id|select_type|table|partitions|type|possible_keys             |key                       |key_len|ref    |rows   |filtered|Extra|
--+-----------+-----+----------+----+--------------------------+--------------------------+-------+-------+-------+--------+-----+
 1|SIMPLE     |c    |          |ALL |PRIMARY                   |                          |       |       |4270364|   100.0|     |
 1|SIMPLE     |cb   |          |ref |customer_balances_c_id_IDX|customer_balances_c_id_IDX|8      |db.c.id|      1|   100.0|     |
1
2
3
4

# filter(读取和过滤占比)

表示选取的行和读取的行占比,例如下面这句SQL:

explain select * from  s1 WHERE key1 > '1' and s1.common_field ='1';
1

从笔者执行计划来看,可能会扫描49902,只有大约10%的符合要求:

该查询在单表查询中没有太大意义,但是在连接查询中就比较有参考价值了,例如下面这句SQL:

explain
 select
	*
from
	s1
inner join s2 on
	s1.key1 = s2.key1
WHERE
	s1.common_field = 'a'
1
2
3
4
5
6
7
8
9

从执行计划可以看出s1作为驱动表大约扫描99805列数据,有10%符合要求,而被驱动表s2过滤值为1和100%比例,这意味着针对被驱动表的查询次数可能是99805*0.1大约9980次。

# 小结

通过本文的探索,我们深入了解了MySQL中的EXPLAIN关键字的重要性和作用。EXPLAIN不仅可以帮助我们分析查询执行计划,还可以为我们提供优化查询性能的关键线索。

通过解读EXPLAIN的输出结果,我们学会了如何识别潜在的性能瓶颈,并优化查询以提高数据库的效率和响应速度。了解索引的使用、表连接顺序以及访问类型等信息,能够帮助我们更好地优化查询并避免常见的查询性能问题。

在实际应用中,不断深入学习和理解EXPLAIN的输出结果,结合实际场景进行优化实践,将为我们的数据库应用带来明显的性能改善和优势。通过不断优化查询性能,我们可以提升数据库系统的整体效率,提供更好的用户体验和服务质量。

在今后的数据库开发和维护工作中,让我们继续积极运用EXPLAIN关键字,不断优化查询执行计划,提升数据库性能,为应用程序的稳定性和可靠性打下坚实的基础。

我是 sharkchili ,CSDN Java 领域博客专家,mini-redis的作者,我想写一些有意思的东西,希望对你有帮助,如果你想实时收到我写的硬核的文章也欢迎你关注我的公众号: 写代码的SharkChili 。

同时也非常欢迎你star我的开源项目mini-redis:https://github.com/shark-ctrl/mini-redis (opens new window)

因为近期收到很多读者的私信,所以也专门创建了一个交流群,感兴趣的读者可以通过上方的公众号获取笔者的联系方式完成好友添加,点击备注 “加群” 即可和笔者和笔者的朋友们进行深入交流。

# 参考

《MySQL是怎样运行的:从根儿上理解MySQL》

编辑 (opens new window)
上次更新: 2026/03/26, 01:05:31
MySQL 索引进阶指南:深入探秘关键知识点
深入剖析 MySQL 某条执行过程

← MySQL 索引进阶指南:深入探秘关键知识点 深入剖析 MySQL 某条执行过程→

最近更新
01
基于EasyExcel实现高效导出
03-25
02
从开源框架中学习那些实用的位运算技巧
03-25
03
浅谈分布式架构设计思想和常见优化手段
03-25
更多文章>
Theme by Vdoing | Copyright © 2025-2026 Evan Xu | MIT License | 桂ICP备2024034950号 | 桂公网安备45142202000030
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式
×
×