MySQL训练营-如何判断SQL的主要消耗阶段

news/2025/2/5 21:07:37/文章来源:https://www.cnblogs.com/cnyuyang/p/18700148

慢查询分析思路

  1. 确认是锁还是执行消耗

  2. 对于执行消耗,分析执行过程

基础知识回顾

InnoDB 聚簇索引结构

CREATE TABLE `t1` (`id` int NOT NULL AUTO_INCREMENT,`a` int DEFAULT NULL,`b` int DEFAULT NULL,`c` int DEFAULT NULL,PRIMARY KEY (`id`),KEY `a` (`a`),KEY `bc` (`b`,'c')
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4;

索引结构为B+树,只有主键索引的叶子结点带有数据,通过索引a获取数据时,只能先获取到id,回表在主键索引上回表进行查找数据行。索引bc为联合索引,非叶子结点上有同时保存了两个字段。

在索引树上能进行的操作:

  • index lookup:点查

  • index range scan:范围扫描(B+树特性)

  • table scan:全表扫描,扫描主键的叶子结点

  • index skip scan:索引跳跃扫描

索引跳跃扫描

Index Skip Scan(索引跳跃扫描)是数据库系统中一种特殊的索引扫描方式,主要用于优化查询性能,下面从适用场景、工作原理、示例、优缺点几个方面详细介绍:

适用场景

  • 复合索引:当表上存在复合索引(由多个列组成的索引),且查询语句仅引用了复合索引中的部分列,尤其是没有引用复合索引的前导列时,数据库可能会考虑使用 Index Skip Scan。
  • 前导列值唯一值较少:如果复合索引的前导列的唯一值数量相对较少,使用 Index Skip Scan 可以避免全表扫描,提高查询效率。

工作原理

  1. 确定复合索引:首先,数据库需要识别出满足条件的复合索引。例如,对于一个复合索引 (col1, col2),查询语句中可能只涉及 col2 列。
  2. 划分前导列值:数据库会对复合索引的前导列(如 col1)的所有唯一值进行枚举。
  3. 逐值扫描:针对前导列的每个唯一值,数据库会在索引中查找满足查询条件的 col2 列的值,就好像跳过了前导列的筛选过程,直接对后续列进行扫描。
  4. 合并结果:最后,将每次扫描得到的结果合并起来,作为最终的查询结果。

示例

假设有一个表 sales,其结构如下:

CREATE TABLE sales (region VARCHAR(50),product VARCHAR(50),amount DECIMAL(10, 2),INDEX idx_region_product (region, product)
);

如果执行以下查询:

SELECT product, SUM(amount)
FROM sales
GROUP BY product;

在这个查询中,没有使用复合索引 idx_region_product 的前导列 region。如果 region 列的唯一值数量较少,数据库可能会使用 Index Skip Scan 来优化查询。具体过程如下:

  • 数据库会枚举 region 列的所有唯一值,例如 'North''South''East''West'
  • 对于每个 region 值,在索引中查找满足条件的 product 列的值,并计算 amount 的总和。
  • 最后将所有 region 值对应的结果合并起来,得到最终的查询结果。

优点

  • 提高查询性能:在某些情况下,Index Skip Scan 可以避免全表扫描,减少磁盘 I/O 操作,从而提高查询效率。
  • 充分利用索引:即使查询没有使用复合索引的前导列,也可以利用复合索引进行查询,提高索引的利用率。

缺点

  • 开销较大:由于需要枚举前导列的所有唯一值,并进行多次扫描,Index Skip Scan 的开销相对较大。如果前导列的唯一值数量较多,性能可能会受到影响。
  • 优化器选择:数据库优化器需要根据具体情况判断是否使用 Index Skip Scan。如果优化器判断失误,可能会导致性能下降。

执行器单元操作演示及相应的数据结构

  1. filter:where条件过滤
  2. temporary/materialize:中间会创建临时表/物化
    • group by
    • distinct
    • sum/avg

group by存在不需要创建临时表情况:先order by在group by,即输入是有序的时候。

  1. 排序
    • qsort:快排时间复杂度Mlog(M)
    • prioriy queue:堆排序,当语句中出现where ... limit N,时间复杂度Mlog(N),当N远远小于M时,效率比快排高。当 1.没有limit语句 2. 所需内存大于sort_buffer_size 不适用该排序算法。
    • merge sort:所需内存大于sort_buffer_size时,会讲计算结果临时存放至磁盘。

案例,数据准备:

create table t1(id int primary key auto_increment, a int , b int, c int , index (a), index bc(b,c))engine=innodb;
insert into t1(a,b,c) values(1,1,1),(2,2,2),(3,3,3),(4,4,4); 
DROP PROCEDURE IF EXISTS insert_data;-- 创建存储过程
DELIMITER //
CREATE PROCEDURE insert_data()
BEGINDECLARE i INT DEFAULT 1;WHILE i <= 12 DOinsert into t1(a,b,c) select a,b,c from t1;SET i = i + 1;END WHILE;
END //
DELIMITER ;-- 调用存储过程来执行插入操作,重复插入到16384行 
CALL insert_data(); 
insert into t1(a,b,c) values(5,5,5);
insert into t1(a,b,c) select a,b,c from t1;
insert into t1(a,b,c) select a,b,c from t1; //总共65540行+------+----------+
| a    | count(1) |
+------+----------+
|    1 |    16384 |
|    2 |    16384 |
|    3 |    16384 |
|    4 |    16384 |
|    5 |        4 |
+------+----------+

分析以下执行

select c from t1 where a=3 and b>1 order by b limit 300,10\G

首先在索引的选择上,选择a的原因是a = 3的条数小于b > 1。

其次会使用堆排序,因为存在limit语句。

验证:

explain analyze select c from t1 where a=3 and b>1 order by b limit 300,10\G

执行结果:

mysql> explain analyze select c from t1 where a=3 and b>1 order by b limit 300,10\G
*************************** 1. row ***************************
EXPLAIN: -> Limit/Offset: 10/300 row(s)  (cost=1631 rows=10) (actual time=21..21 rows=10 loops=1)-> Sort: t1.b, limit input to 310 row(s) per chunk  (cost=1631 rows=30206) (actual time=21..21 rows=310 loops=1)-> Filter: (t1.b > 1)  (cost=1631 rows=30206) (actual time=4.66..19.7 rows=16384 loops=1)-> Index lookup on t1 using a (a=3)  (cost=1631 rows=30206) (actual time=4.66..18.9 rows=16384 loops=1)1 row in set (0.02 sec)
  • 调大sort_buffer_size是否能提高性能?

不能,因为排序都是在内存中进行的堆排序。

  • 堆排序是否导致结果不一样

是的,堆排序是不稳定排序。示例比较简单,若b,c没有关系,是可能出现前后两次执行结果不一样情况。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/879262.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

windows本地部署deepseek-R1模型并接入wx

1、本地部署deepseek-R1模型 通过官网 https://ollama.com 下载安装 ollama 选择自身GPU显存适合的 模型,这里我用的8b ollama run deepseek-r1:8b2、hook wechat接入对话 通过项目 https://github.com/ngc660sec/NGCBot hook wechat想必这种方式会比docker+cow网页版登录的方…

口胡赛 2025.2.5

T1 首先不要 \(p\) 这个肯定是不能枚举 \(p\) 再直白处理的,因为最快的 Floyd 都要 \(O(n^3)\) 这样。 那么不要 \(p\) 的信息是合并得来的,但是直接合并复杂度也不够,考虑使用经典分治,先加入 \([l,mid]\) 然后递归 \((mid,r]\),撤销 \([l,mid]\),加入 \((mid,r]\),在递…

linux系统语言修改

查看当前系统语言查看已有的语言包修改linux系统语言 指令: gvim /etc/locale.conf 将“ ”的内容替换即可:

基于ESP32的桌面小屏幕实战[7]:第一个工程Hello world!以及打印日志

摘要 本文构建下载了示例工程hello world,并在其中调用esp_log.h中的日志函数打印日志。 1. 创建工程 打开esp目录,把hello world文件夹复制到当前文件夹,并打开hello world文件夹。 cd ~/esp cp -r esp-idf/examples/get-started/hello_world . cd ~/esp/hello_world使用命…

基于Python的Selenium详细教程

本文使用环境:windows11、Python 3.10.5、PyCharm 2022.1.3、Selenium 4.3.0 需要你懂的技术:Python、HTML、CSS、JavaScript一、PyCharm安装配置Selenium本文使用环境:windows11、Python 3.10.5、PyCharm 2022.1.3、Selenium 4.3.0需要你懂的技术:Python、HTML、CSS、Java…

作业01

public class HomeWork01 {public static void main(String[] args) {int n1 = 13;int n2 = 17;int n3 = n1+n2;System.out.println("n3 = "+ n3);//30int n4 = 38;int n5 = n4-n3;System.out.println("n5 ="+n5);//8}}

CROS错误,xhr类型

解决方案:向Web.config里添加此项设置即可

2025省选模拟9

不知道啥2025省选模拟9 网络流专场是吧😅 Delov 的 npy 们 原题链接 一眼网络流,然后不会了。 发现正常顺着限制做做不了,考虑将限制转化一下,以 L 操作为例。 在 \(a_i\) 左侧的点中不超过 \(b_i\) 个,等价于从左往右数第 \(b_i+1\) 个点在 \(a_i\) 右侧。 但还是不好做…

海外社交媒体运营卡成狗?云手机一键“救场”

海外社交媒体运营卡成狗?云手机一键“救场” 在海外社交媒体运营中,运营人员往往会遇到各种挑战,导致运营效率低下,甚至感觉“卡成狗”。而云手机作为一种流行的成熟普及技术工具,可以为海外社交媒体运营带来一定的帮助,实现一键“救场”。以下是对云手机在海外社交媒体运…

MyBatis resultmap结果映射

创建数据库和实体类 首先创建数据库student和teacher,并且每个学生对应一个老师,一个老师可以对应多个学生,数据库如下图: 创建实体类Student1 package com.loubin.pojo;2 3 public class Student {4 private int id;5 private String name;6 7 Teacher teach…

Linguistics-English-Textbooks: 上海外教社: 高校英语专业系列教材(修订版)

新世纪高校英语专业系列教材(修订版) https://we.sflep.com/books/newcenturymajor1.aspx教材特色 配套资源 特点 秉以新《国标》指导下的英语专业课程改革为导向精心架构,体系完备。 凝聚海内外英语专业教育界专家学者智慧,教材编写高屋建瓴、深入 浅出. 兼顾语言基本技能…