学习总结录 学习总结录
首页
归档
分类
标签
  • Java基础
  • Java集合
  • MySQL
  • Redis
  • JVM
  • 多线程
  • 计算机网络
  • 操作系统
  • Spring
  • Kafka
  • Elasticsearch
  • Python
  • 面试专题
  • 案例实践
  • 工具使用
  • 项目搭建
  • 服务治理
  • ORM框架
  • 分布式组件
  • MiniSpring
  • 设计模式
  • 算法思想
  • 编码规范
友链
关于
GitHub (opens new window)
首页
归档
分类
标签
  • Java基础
  • Java集合
  • MySQL
  • Redis
  • JVM
  • 多线程
  • 计算机网络
  • 操作系统
  • Spring
  • Kafka
  • Elasticsearch
  • Python
  • 面试专题
  • 案例实践
  • 工具使用
  • 项目搭建
  • 服务治理
  • ORM框架
  • 分布式组件
  • MiniSpring
  • 设计模式
  • 算法思想
  • 编码规范
友链
关于
GitHub (opens new window)
  • Java基础

  • Java集合

  • MySQL

    • MySQL深入01-查询语句
      • 查询语句执行流程
      • 连接器
      • 查询缓存
      • 分析器
      • 优化器
      • 执行器
      • 参考
    • MySQL深入02-更新语句
    • MySQL深入03-事务隔离
    • MySQL深入04-深入浅出索引
    • MySQL深入05-全局锁、表锁、行锁
    • MySQL深入06-事务隔离再探
    • MySQL深入07-普通索引和唯一索引
    • MySQL深入08-为什么会选错索引
    • MySQL深入09-字符串字段加索引
    • MySQL深入10-脏页刷新
    • MySQL深入11-数据库表空间回收
    • MySQL深入12-count()
    • MySQL深入13-order by
    • MySQL深入14-正确显示随机消息
    • MySQL深入15-索引失效案例分析
    • MySQL深入16-查询一行数据执行慢
    • MySQL深入17-幻读
    • MySQL深入18-改一行语句锁问题
    • MySQL深入19-暂时提高数据库性能方案
    • MySQL深入20-这么保证数据不丢
    • MySQL深入21-主备一致的保证
    • MySQL深入22-高可用性的保证
    • MySQL深入23-备库延迟好几个小时
    • MySQL深入24-主库出问题,从库这么办
    • MySQL深入25-读写分离的过期读问题
    • MySQL深入26-判断数据库是否出问题
    • MySQL深入27-误删数据的处理方案
    • MySQL深入28-kill不掉的语句
    • MySQL深入29-查询对内存的影响
    • MySQL深入30-join深入
    • MySQL深入31-join语句优化
    • MySQL深入32-临时表深入
    • MySQL深入33-内部临时表何时使用
    • MySQL深入34-InnoDB和Memory
    • MySQL深入35-自增主键为什么不连续
    • MySQL深入36-insert语句的锁
    • MySQL深入37-如何快速复制一张表
    • MySQL深入38-grant和flush privileges
    • MySQL深入39-分区表
    • MySQL深入40-自增id用完如何处理
  • Redis

  • JVM

  • 多线程

  • 计算机网络

  • Spring

  • Kafka

  • Elasticsearch

  • Python

  • 面试专题

  • 知识库
  • MySQL
旭日
2023-03-26
目录

MySQL深入01-查询语句

# 查询语句执行流程

首先我们来看一下MySQL存在那些组件:

image-20220301215413030

可以大致看出MySQL一共分为两大部分

  • Server层:包括连接器、查询缓存、分析器、优化器、执行器等,涵盖 MySQL 的大多数核心服务功能,以及所有的内置函数(如日期、时间、数学和加密函数等),所有跨存储引擎的功能都在这一层实现,比如存储过程、触发器、视图等
  • 存储引擎:就是负责数据的存储读写,一般我们在开发中我们都是把引擎类型设置为InnoDB。不同的存储引擎使用的是同一个server层

接下来我们依次对每个部分进行分析。

# 连接器

通常我们去链接数据库,我们会使用一下语句:

mysql -u账号 -p密码

这时候发挥作用的就是连接器,连接器开始对我们的身份进行验证:

  • 账号或密码错误,我们就会收到一个错误信息。
  • 账号和密码正确,就会去权限表里面查询到该账号所拥有的权限。

一旦链接成功之后,权限会一直跟着该链接走,哪怕在链接之后该用户的权限变化了,也不会影响到已经链接的权限,只有当用户重新链接之后,才会刷新权限。

现在我们可以通过show processlist;来查询我们的链接:

image-20220301220836813

可以看到Sleep表示该链接处于空闲状态下,该链接就是空闲链接。

客户端如果太长时间没动静,连接器就会自动将它断开。这个时间是由参数 wait_timeout 控制的,默认值是 8 小时。

而所谓的长链接就是指连接成功后,如果客户端持续有请求,则一直使用同一个连接。短连接则是指每次执行完很少的几次查询就断开连接,下次查询再重新建立一个。

使用长链接会存在一个问题那就是MySQL内存占用特别快,这是因为 MySQL 在执行过程中临时使用的内存是管理在连接对象里面的。这些资源会在连接断开的时候才释放。

解决方案:

  • 定期断开长连接。使用一段时间,或者程序里面判断执行过一个占用内存的大查询后,断开连接,之后要查询再重连。

# 查询缓存

查询缓存这个很容易理解,如果查询语句在查询缓存中,那么MySQL会把上一次查询的结果保存下来,下次我们再查询的时候,如果还是相同的sql语句,就只需要从缓存中把对应sql语句的查询结果返回即可。

如果查询语句不在查询缓存中,就会继续后面的执行阶段,执行完成后,执行结果会被存入查询缓存中。

大多数情况下不要使用查询缓存:

查询缓存的失效非常频繁,只要有对一个表的更新,这个表上所有的查询缓存都会被清空。因此很可能费劲地把结果存起来,还没使用呢,就被一个更新全清空了。对于更新压力大的数据库来说,查询缓存的命中率会非常低。

设置不适用缓存查询:

  • 可以将参数 query_cache_type 设置成 DEMAND,这样对于默认的 SQL 语句都不使用查询缓存

  • 对于特定的语句要使用缓存查询:

    SELECT SQL_CACHE * FROM `sys_user` WHERE username = "admin";
    

需要注意的是,MySQL 8.0 版本直接将查询缓存的整块功能删掉了,也就是说 8.0 开始彻底没有这个功能了。

# 分析器

如果没有命中查询缓存,那么从现在开始才真正执行我们的查询语句。

对于分析器,正所谓分析就是查看你所输入的sql语句是否正确,而分析器主要做两件事情:

  • 词法分析 - 分析出输入的字符串分别是什么,代表什么。
  • 语法分析 - 判断你输入的这个 SQL 语句是否满足 MySQL 语法。

如果表 T 中没有字段 k,而你执行了这个语句 select * from T where k=1, 那肯定是会报“不存在这个列”的错误: “Unknown column ‘k’ in ‘where clause’”。这个错误就是分析器阶段报出来的。

# 优化器

经过了分析器阶段之后,MySQL可以判断出你的SQL语句已经没有问题了,并且也知道你需要做的事情了,但是做一件事情有多种方案,这时候MySQL还需要选择出最优的方案。

优化器是在表里面有多个索引的时候,决定使用哪个索引;或者在一个语句有多表关联(join)的时候,决定各个表的连接顺序。

优化器阶段完成后,这个语句的执行方案就确定下来了,然后进入执行器阶段。

# 执行器

MySQL 通过分析器知道了你要做什么,通过优化器知道了该怎么做,于是就进入了执行器阶段,开始执行语句。

开始执行的时候,会对你所查询的表进行权限判断,如果没有查询的权限,那么就会返回没有权限的错误。

如果有权限,就打开表继续执行。打开表的时候,执行器就会根据表的引擎定义,去使用这个引擎提供的接口。

对于我们的语句:

SELECT * FROM `sys_user` WHERE username = "admin";
  • 调用InnoDB 引擎接口取这个表的第一行,判断username是不是等于admin,如果不是就取下一行,如果是则将这一行数据保存在结果集中。
  • 调用引擎接口取“下一行”,重复相同的判断逻辑,直到取到这个表的最后一行。
  • 执行器将上述遍历过程中所有满足条件的行组成的记录集作为结果集返回给客户端。

你会在数据库的慢查询日志中看到一个 rows_examined 的字段,表示这个语句执行过程中扫描了多少行。这个值就是在执行器每次调用引擎获取数据行的时候累加的。

# 参考

MySQL 实战 45 讲-极客时间 (opens new window)

#MySQL
上次更新: 2024/06/29, 15:13:44
Java集合-ConcurrentHashMap
MySQL深入02-更新语句

← Java集合-ConcurrentHashMap MySQL深入02-更新语句→

最近更新
01
基础概念
10-31
02
Pytorch
10-30
03
Numpy
10-30
更多文章>
Theme by Vdoing | Copyright © 2021-2024 旭日 | 蜀ICP备2021000788号-1
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式