使用explain优化慢查询的业务场景分析
- 问:你最害怕的事情是什么?
- 答:搓澡
- 问:为什么?
- 答:因为有些人一旦错过,就不在了

Explain 这个词在不同的上下文中有不同的含义。在数据库查询优化的上下文中,"EXPLAIN" 是一个常用的 SQL 命令,用于显示 SQL 查询的执行计划。执行计划是数据库如何执行查询的一个详细描述,包括它将使用哪些索引、表的连接顺序、表的扫描方式等信息。
在 SQL 中,使用 "EXPLAIN" 可以提供以下字段的信息:
- id: 表示查询中的各个部分的标识符。
- select_type: 查询类型,比如简单查询、联合查询、子查询等。
- table: 涉及的表名。
- partitions: 查询涉及的分区信息。
- type: 连接类型,如全表扫描、索引扫描等。
- possible_keys: 可能使用的索引列表。
- key: 实际使用的索引。
- key_len: 使用的索引长度。
- ref: 索引列上使用的列或常量。
- rows: 估计需要检查的行数。
- filtered: 行过滤的百分比。
- Extra: 额外信息,可能包含诸如"Using filesort"、"Using temporary"等信息。
下面,V 哥通过两个案例来详细说明一下如何使用 Explain来优化 SQL。
案例一:
场景设定
假设我们有一个电子商务网站的数据库,其中有一个名为 orders 的表,它记录了用户的订单信息。表结构大致如下:
id: 订单的唯一标识符
user_id: 下单用户的ID
product_id: 购买的产品ID
order_date: 下单日期
quantity: 购买数量
问题
我们需要查询2024年1月1日之后所有用户的订单总数。
原始 SQL 查询
SELECT COUNT(*) FROM orders WHERE order_date > '2024-01-01';
步骤 1: 使用 EXPLAIN 分析查询
首先,我们使用 EXPLAIN 来查看当前查询的执行计划:
EXPLAIN SELECT COUNT(*) FROM orders WHERE order_date > '2024-01-01';
步骤 2: 分析 EXPLAIN 输出
假设 EXPLAIN 的输出显示如下:
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
|---|---|---|---|---|---|---|---|---|---|---|---|
| 1 | SIMPLE | orders | NULL | range | order_date | NULL | NULL | NULL | 10000 | 10.00 | Using where; Using index |
步骤 3: 识别问题
从 EXPLAIN 输出中,我们可以看到:
- type 是 range,这意味着数据库将使用索引进行范围扫描,而不是全表扫描。
- rows 估计为 10000,这可能表示查询需要检查大量行。
- Extra 显示 Using where; Using index,表示使用了索引。
步骤 4: 优化 SQL
尽管查询已经使用了索引,但我们可能希望进一步优化性能。考虑到我们只需要统计总数,而不是具体的订单数据,我们可以:
- 使用索引覆盖扫描:如果 order_date 索引包含 id,则可以避免回表查询,直接在索引中完成统计。
优化后的 SQL 可能如下:
SELECT COUNT(*) FROM orders USE INDEX (order_date) WHERE order_date > '2023-01-01';
步骤 5: 再次使用 EXPLAIN
使用优化后的查询再次运行 EXPLAIN:
EXPLAIN SELECT COUNT(*) FROM orders USE INDEX (order_date) WHERE order_date > '2023-01-01';
步骤 6: 分析优化后的输出
假设优化后的 EXPLAIN 输出显示:
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
|---|---|---|---|---|---|---|---|---|---|---|---|
| 1 | SIMPLE | orders | NULL | index | order_date | order_date | 4 | NULL | 10000 | 10.00 | Using index; Backward index scan |
步骤 7: 评估优化效果
- type 现在是 index,表示使用了索引覆盖扫描。
- Extra 显示 Using index; Backward index scan,表示查询仅使用了索引,没有回表。
通过这些步骤,我们对原始查询进行了分析和优化,提高了查询效率。在实际应用中,可能需要根据具体的数据库结构和数据分布进行更多的调整和优化。
案例二:
我们考虑一个更复杂的场景,涉及到多表查询和联结。
场景设定
假设我们有一个在线教育平台的数据库,其中有两个表:
1. students 表,存储学生信息:
- student_id: 学生ID
- name: 学生姓名
- enrollment_date: 入学日期
2. courses 表,存储课程信息:
- course_id: 课程ID
- course_name: 课程名称
3. 还有一个 enrollments 表,存储学生的课程注册信息:
- enrollment_id: 注册ID
- student_id: 学生ID
- course_id: 课程ID
- enrollment_date: 注册日期
问题
我们需要查询所有在2024年注册了至少一门课程的学生的姓名和他们注册的课程数量。
原始 SQL 查询
SELECT s.name, COUNT(e.course_id) AS course_count
FROM students s
JOIN enrollments e ON s.student_id = e.student_id
GROUP BY s.name;
步骤 1: 使用 EXPLAIN 分析查询
EXPLAIN SELECT s.name, COUNT(e.course_id) AS course_count
FROM students s
JOIN enrollments e ON s.student_id = e.student_id
GROUP BY s.name;
步骤 2: 分析 EXPLAIN 输出
假设 EXPLAIN 的输出如下:
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
|---|---|---|---|---|---|---|---|---|---|---|---|
| 1 | SIMPLE | s | NULL | ALL | NULL | NULL | NULL | NULL | 1000 | NULL | NULL |
| 1 | SIMPLE | e | NULL | ref | student_id | student_id | 5 | students.student_id | 5000 | NULL | Using where |
步骤 3: 识别问题
- students 表使用了全表扫描(type 是 ALL),这意味着查询需要扫描整个 students 表。
- enrollments 表使用了 ref 类型的联结,它使用了 student_id 索引。
步骤 4: 优化 SQL
我们可以通过以下方式优化查询:
- 添加索引:如果 enrollments 表上的 enrollment_date 没有索引,考虑添加一个,以便快速过滤2023年的注册记录。
- 过滤条件:在联结条件中添加过滤条件,减少需要联结的行数。
优化后的 SQL 可能如下:
SELECT s.name, COUNT(e.course_id) AS course_count
FROM students s
JOIN (
SELECT course_id, student_id
FROM enrollments
WHERE enrollment_date >= '2023-01-01'
) e ON s.student_id = e.student_id
GROUP BY s.name;
步骤 5: 再次使用 EXPLAIN
使用优化后的查询再次运行 EXPLAIN。
步骤 6: 分析优化后的输出
假设优化后的 EXPLAIN 输出显示:
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
|---|---|---|---|---|---|---|---|---|---|---|---|
| 1 | PRIMARY | s | NULL | ALL | NULL | NULL | NULL | NULL | 1000 | NULL | NULL |
| 2 | DERIVED | e | NULL | range | enrollment_date | NULL | NULL | NULL | 500 | 10.00 | Using where |
| 1 | SIMPLE | <subquery2> |
NULL | ref | student_id | student_id | 5 | s.student_id | 500 | NULL | Using index |
步骤 7: 评估优化效果
- 子查询 e 现在使用 range 类型扫描,只获取2023年的注册记录,减少了行数。
- 主查询现在使用 ref 类型联结,因为子查询结果已经通过索引 student_id 进行了优化。
通过这些步骤,我们对原始查询进行了分析和优化,减少了需要处理的数据量,提高了查询效率。在实际应用中,可能需要根据具体的数据库结构和数据分布进行更多的调整和优化。
最后
以上是 V 哥在整理的关于 EXPLAIN 在实际工作中的使用,并结合案例给大家作了分析,用熟 EXPLAIN 将大大改善你的 SQL 查询效率,你在工作中还用到哪些业务场景或案例,可以在评论区讨论,或者说出你遇到的问题,V 哥来帮你定位一下问题,关注威哥爱编程,每天精彩内容不错过。
使用explain优化慢查询的业务场景分析的更多相关文章
- SpringCloud | 通过电商业务场景让你彻底明白SpringCloud核心组件的底层原理
本文分为两个部分: Spring Cloud"全家桶"简单介绍. 通过实际电商业务场景,让你彻底明白Spring Cloud几个核心组件的底层原理. Spring Cloud介绍 ...
- mysql性能优化-慢查询分析、优化索引和配置 (慢查询日志,explain,profile)
mysql性能优化-慢查询分析.优化索引和配置 (慢查询日志,explain,profile) 一.优化概述 二.查询与索引优化分析 1性能瓶颈定位 Show命令 慢查询日志 explain分析查询 ...
- 索引优化之Explain 及慢查询日志
索引:本质是数据结构,简单理解为:排好序的快速查找数据结构,以索引文件的形式存储在磁盘中.目的:提高数据查询的效率,优化查询性能,就像书的目录一样.优势:提高检索效率,降低IO成本:排好序的表,降低C ...
- mysql,存储引擎,事务,锁,慢查询,执行计划分析,sql优化
基础篇:MySql架构与存储引擎 逻辑架构图: 连接层: mysql启动后(可以把mysql类比为一个后台的服务器),等待客户端请求,当请求到来后,mysql建立一个一个线程处理(线程池则分配一个空线 ...
- 10个常见触发IO瓶颈的高频业务场景
摘要:本文从应用业务优化角度,以常见触发IO慢的业务SQL场景为例,指导如何通过优化业务去提升IO效率和降低IO. 本文分享自华为云社区<GaussDB(DWS)性能优化之业务降IO优化> ...
- 通过手动创建统计信息优化sql查询性能案例
本质原因在于:SQL Server 统计信息只包含复合索引的第一个列的信息,而不包含复合索引数据组合的信息 来源于工作中的一个实际问题, 这里是组合列数据不均匀导致查询无法预估数据行数,从而导致无法选 ...
- 受教了,memcache比较全面点的介绍,受益匪浅,适用memcached的业务场景有哪些?memcached的cache机制是怎样的?在设计应用时,可以通过Memcached缓存那些内容?
基本问题 1.memcached的基本设置 1)启动Memcache的服务器端 # /usr/local/bin/memcached -d -m 10 -u root -l 192.168.0.200 ...
- CDN 边缘规则,三秒部署、支持定制、即时生效,多种规则覆盖常用业务场景
2017年的最后一周,又拍云进行了一次重要升级,将自定义 Rewrite 升级为"边缘规则".互联网应用场景的日益多样化,简单.方便.快速的根据不同应用场景实现不同的功能变得越来越 ...
- 整理分布式锁:业务场景&分布式锁家族&实现原理
1.引入业务场景 业务场景一出现: 因为小T刚接手项目,正在吭哧吭哧对熟悉着代码.部署架构.在看代码过程中发现,下单这块代码可能会出现问题,这可是分布式部署的,如果多个用户同时购买同一个商品,就可能导 ...
- 【性能优化】优雅地优化慢查询:缓存+SQL修改组合拳
问题描述 单例数据库模式中,后端高并发请求多(读多写少),导致数据库压力过大,关键接口响应变慢,严重影响体验. 需求 减少接口的响应时间. 寻找解决方案 由于问题主要处在数据库压力过大的情况,采用两种 ...
随机推荐
- appium测试混合应用
最近用appium测试公司APP,APP是原生+H5的模式,测试过程中发现大部分H5的页面使用原生的方式可以进行操作,只有少部分H5页面的按钮虽然在uiautomatorviewer的界面能解析出来, ...
- 【zabbix】snmp监控linux主机
1.安装net-snmp # yum install -y net-snmp 2.配置文件 /etc/snmp/snmpd.conf 添加如下内容 view systemview included . ...
- .NET有哪些好用的定时任务调度框架
前言 定时任务调度的相关业务在日常工作开发中是一个十分常见的需求,经常有小伙伴们在技术群提问:有什么好用的定时任务调度框架推荐的?今天大姚给大家分享5个.NET开源.简单.易用.免费的任务调度框架,帮 ...
- NASM中的ALIGN ALIGNB SECTALIGN
ALIGN与ALIGNB NASM中的ALIGN与ALIGNB是用来字节对齐的,它们接收2个参数,第一个参数是必须的,表示对齐的字节数(必须是2的幂),第二个参数是可选的,表示为了对齐而进行填充的内容 ...
- 🔥🔥🔥httpsok-v1.8.0 SSL证书自动续签就应该这么简单
httpsok-v1.8.0 SSL证书自动续签就应该这么简单 简介 一行命令,一分钟轻松搞定SSL证书自动续期 httpsok 是一个便捷的 HTTPS 证书自动续签工具,专为 Nginx 服务器设 ...
- HBase Meta 元信息表修复实践
作者:vivo 互联网大数据团队 - Huang Guihu.Chen Shengzun HBase是一款开源高可靠.高可扩展性.高性能的分布式非关系型数据库,广泛应用于大数据处理.实时计算.数据存储 ...
- ECMAScript 语言规范每年都会进行一次更新,而备受期待的 ECMAScript 2024 将于 2024 年 6 月正式亮相。目前,ECMAScript 2024 的候选版本已经发布,为我们带来了一系列实用的新功能。
Promise.withResolvers 使用 Promise.withResolvers() 关键的区别在于解决和拒绝函数现在与 Promise 本身处于同一作用域,而不是在执行器中被创建和一次性 ...
- js图片懒加载,在不做分页的情况下的解决方案
Intersection Observer API 1.注意点 一般都是后端返回数据, 用 this.$nextTick(() => { this.handleScroll(); }); 确保d ...
- 4G EPS 中的 Bearer
目录 文章目录 目录 前文列表 承载的内涵 EPS Bearer QoS QoS 的关键参数 APR GBR.MBR AMBR UE 是如何选择 EPS Bearer 的? E-RAB Radio B ...
- Angular的管道
Angular的管道可以看作成是一个数据格式化展示的工具.管道可以将数据格式化显示,而不改变源数据.获取数据可能简单到创建一个局部变量就行,也可能复杂到从WebSocket中获取数据流.一旦取到数据, ...