01 | 基础架构:一条SQL查询语句是如何执行的?

FAQ

画出 MySQL 的基本架构图

image.png

Server 层和存储引擎层各自有哪些组件?

Server 层

  • 连接器
  • 查询缓存
  • 分析器
  • 优化器
  • 执行器
  • 所有内置函数(日期、时间、数学和加密函数等)
  • 所有跨存储引擎的功能(存储过程、触发器、视图等)

存储引擎层

  • 负责数据的存储和读取

连接器的作用?

  • 连接器负责跟客户端建立连接、获取权限、维持和管理连接
  • 获取权限:连接器从权限表中获取用户所拥有的权限,
    • 如果是全局权限,则将权限信息加载到内存 acl_users 数组中,并且将权限信息拷贝一份到线程对象中,连接中的权限判断以线程对象中保存的权限信息作为依据,因此全局权限的 grant/revoke 只对新建连接生效,对已存在的连接不生效。
    • 如果是库级别权限,则将数据表的权限信息加载到内存 acl_dbs 数组中,之后,权限判断逻辑以内存 acl_dbs 数组中的权限信息作为依据,不过存在一种特殊情况,使用 use db 命令时,会将数组 acl_dbs 中的用户权限信息拷贝一份保存到会话变量中,之后,在该会话中的权限检验以该会话变量中保存的用户权限为准。
    • 如果是表、列权限,则将权限信息加载到 column_priv_hash 哈希结构中,之后权限判断,以该哈希结构中存储的数据为准,对已建立的连接立刻生效。
权限范围 存储权限信息的数据表 存储权限信息的内存数据结构 grant/revoke 语句对数据表和内存权限信息的影响 特殊逻辑 grant/revoke对已建立连接的影响 对新建立连接的影响
全局权限 mysql.user acl_users 每次 grant/revoke 时,不仅修改数据表,也会同步修改内存 acl_users 数组 mysql 会为连接维护一个线程对象,并将内存 acl_users 数组中的用户权限信息拷贝到线程对象中,在此之后,此连接中的所有全局权限的判断,直接使用线程对象中保存的权限位 不影响已建立连接 立刻生效
库级别权限 mysql.db acl_dbs 每次 grant/revoke 时,不仅修改数据表,也会同步修改内存 acl_dbs 数组 use db 语句会将获取到的库权限信息保存在会话变量中,在此之后,此连接中的所有库权限的判断,都直接使用该会话变量中保存的权限位
- 不影响执行过 use db 命令的已建立连接
- 对未指定库的连接,立即生效
立刻生效
表和列权限 mysql.tables_priv, mysql.columns_priv column_priv_hash 每次 grant/revoke 时,不仅修改数据表,也会同步修改内存 column_priv_hash 结构 立刻生效 立刻生效
  • 针对表级别的权限修改,无论连接是新建的还是后来创建的,命令立马生效,
  • 针对全局权限或者库级别权限的修改,已有的连接不受影响(特殊情况:库级别权限修改并且使用 use db 命令,一般程序都会使用该命令),后续新建的连接才会生效。

什么是长连接、短连接?

如果客户端使用了连接池,则客户端和RDS实例之间的连接为长连接(建立连接并读写完成后不会主动断开的连接),反之则为短连接(建立连接并读写完成后主动断开的连接)。

使用长连接,为什么有时可能会导致 MySQL 占用内存涨得特别快,从而导致内存占用太大,被系统强行杀掉(OOM)

因为 MySQL 在执行过程中临时使用的内存是在连接对象里进行管理的。而在默认情况下,连接对象中申请的资源会在连接断开时才会释放(释放给了系统还是 MySQL?)。因此如果长连接长时间不断开连接,可能导致 MySQL 内存占用太大,从而被系统强行杀掉(OOM)

如何解决长连接长时间不断开,导致连接内存占用太大,进而导致 MySQL 内存占用太大,从而被系统强行杀掉?

两种方案

  1. 定期断开长连接。使用一段时间,或者在程序里判断执行过一个占用内存的大查询后,断开连接,之后查询再重建连接
  2. 在 MySQL 5.7 或更新版本,每次执行完一个占用内存较大的操作后,执行 [mysql_reset_connection](https://www.yuque.com/docs/share/7ff2ccda-65c6-4dcb-b93c-f7d08f7fecd7?# 《cmd_reset_connection》) 来重新初始化连接资源。并且不需要重连和重新校验权限,但会将连接恢复到刚刚创建完成时的状态
    1. C API:mysql_reset_connection
    2. Python API:cmd_reset_connection(无法重新初始化连接资源,释放不了所占用的内存,只能重置用户和系统变量)

[wait_timeout and interactive_timeout 参数的区别和联系](https://www.yuque.com/docs/share/26d83ed1-bcff-4211-a315-1c32b2745a1e?# 《wait_timeout and interactive_timeout 参数的区别和联系》)

为什么叫交互式和非交互式连接?通俗解释不知道?

  • 交互式连接:通过 mysql 客户端 与 mysql server 建立的连接是交互式连接
  • 非交互式连接:不是通过 mysql 客户端,而是通过 jdbc 等方法与 mysql server 建立的连接称为非交互式连接

会话级变量 wait_timeout

参数 作用
wait_timeout 非交互式连接建立完成后,使用过程中的等待时间(单位:秒)
interactive_timeout 交互式连接建立完成后,使用过程中的等待时间(单位:秒)
  1. 交互式连接的会话变量 wait_timeout 和 interactive_timeout 都继承自全局变量 interactive_timeout
  2. 非交互式连接的会话变量 wait_timeout 和 interactive_timeout 分别继承自全局变量 wait_timeout 和 interactive_timeout
  3. 无论是交互式还是非交互式连接,连接闲置阈值都由会话变量 wait_timeout 控制,与会话变量 interactive_timeout 无关。

查询缓存中存储的是什么内容?

查询缓存中存储着执行过的语句和其结果,并以 key-value 的形式存储在内存中,其中 key 对应查询的语句,value 对应查询的结果。当查询语句能够在查询缓存中匹配到的话,则直接返回查询结果。

为什么不建议使用查询缓存?

查询缓存的失效机制:只要表上有一个更新,那么查询缓存中关于这张表的所有查询缓存都将清空,这对于更新频繁的数据库来说,查询缓存的命中率会非常低,因此查询缓存基本没用

分析器的作用?

解析 SQL 语句,以获悉该 SQL 语句要做什么。

分析器中词法解析的作用?

SQL 语句由多个字符串和空格、换行组成,词法解析会将 SQL 中的字符串识别出来,并确定每个字符串代表的含义(表、字段、关键字等)
比如,查询语句 select id from t where id = 10,词法解析会将字符串 ”t“ 识别为”表名 t“,字符串 ”id“ 识别为“列 id”

分析器中语法解析的作用?

语法解析器根据语法规则判断 SQL 语句是否满足 MySQL 语法

优化器的作用?

  • 优化器在表中有多个索引时,决定使用哪个索引
  • 或者在一个语句有多表关联时,决定各个表的连接顺序

执行器的作用?

调用存储引擎提供的接口去读写数据

执行器执行查询前,需要判断是否有查询语句中相关表的查询权限,为什么不将这个权限校验的过程放到优化器或分析器中去做?

  • 连接阶段只是“获得权限信息”, 真正开始查询动作,才判断“有没有操作这个表的权限”
  • 连接阶段是去系统表读数据,结果放在变量,执行器使用这个变量
posted @ 2023-06-08 16:16  甲兵匪已  阅读(81)  评论(0编辑  收藏  举报