Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
git-zjx opened this issue Jul 11, 2019 · 0 comments

Comments

@git-zjx
Copy link
Owner

commented Jul 11, 2019

MySQL 大体可以分为 Server 层和存储引擎层

  • Server 层包括 连接器、查询缓存、分析器、优化器和执行器等,涵盖 MySQL 的大部分核心功能,所有的内置函数(例如:日期,数字和加密函数)和所有的跨存储引擎的功能(例如:存储过程、触发器和视图)都在这层

  • 存储引擎层负责数据的读取和存储

连接过程

1. 连接器

客户端通过连接器和服务端进行连接,经过 TCP 三次握手之后,连接器开始验证客户端身份,验证通过之后,连接器会去权限表获取权限,之后这个连接里面的所有权限判断都依赖此时获取的权限(也就意味着就算管理员修改了该用户的权限,也不会影响该连接)
连接完成之后,如果不使用会处于空闲状态,使用 show processlist\G 可以查看。 如果客户端长时间没有响应,连接器会断开该连接,时间由 wait_timeout 控制,默认为 8 小时

长连接和短链接

数据库里面,长连接是指连接成功之后,如果客户端持续有请求,则使用同一个连接。短连接是指每次执行很少的几次查询之后就断开连接,下一次查询再重新建立连接

建议尽量减少连接的创建动作,因为创建连接的过程通常比较复杂。但因为 MySQL 在执行过程中临时使用的内存是管理在连接对象里面的,这些资源会在连接断开的时候释放,所以长连接积累下来会导致内存占用过大,会被系统强行杀掉(OOM)。可以考虑一下两种方案解决

  • 定期断开长连接
  • MySQL 5.7 或更新版本可以使用 mysql_reset_connection 重新初始化连接资源,该操作只会将连接还原成初始状态,不会再去重连和重做权限验证

2. 查询缓存

MySQL 拿到查询请求之后,会先去查询缓存内查找之前该查询是否执行过,执行过的查询及其结果会以 key-value 的形式存储于内存中,如果在就直接返回,不在就执行下一阶段

查询缓存的弊大于利

查询缓存失效的非常频繁,只要表有改动,在这个表上的所有查询缓存都会失效
可以设置 query_cache_typeDEMAND,这样之后默认的语句都不会使用查询缓存,如果确定使用查询缓存可以使用 SQL_CACHE 显示指定

3. 分析器

若查询缓存没有命中,就会到达分析器,分析器会进行词法分析和语法分析让 MySQL 知道你要做什么。
词法分析会分析出一条 SQL 语句中的字符串是什么,代表什么,从 SQL 语句中 SELECT 关键字识别出这是一条查询语句,把字符串 T 识别成表名 T ,字符串 ID 识别成列 ID(所以不存在列的错误会在分析器内抛出)。
根据词法分析的结果,语法分析会根据语法规则判断该 SQL 是否符合语法,如果语法错误会抛出,而且语法错误会提示第一个错误出现的位置

4. 优化器

进过分析器处理之后会进入优化器,MySQL 会在开始执行之前对 SQL 语句进行优化处理。
优化器主要决定多个索引时使用哪个索引,JOIN 时决定连接顺序等,选择完成之后进入执行器

5. 执行器

执行器会在开始执行前判断是否有执行查询的权限(查询缓存命中后,会在返回结果时也做一次权限判断。也会在优化器之前做一次权限判断),没有权限会抛出权限错误,有权限会打开表继续执行

执行流程

  • 调用引擎接口读取表的第一行,判断值是否符合,不符合跳过,符合就存放在结果集中
  • 调用引擎接口读取下一行,执行相同逻辑,直到表的最后一行
  • 执行器将结果集返回给客户端

问题

  1. 一个没有select权限的用户,执行select * from T where k=1,报错“select command denied”,并没有报错“unknown column”,是不是可以说明是在打开表之后才判断读取的列不存在?
    这个是一个安全方面的考虑。你想想一个用户如果没有查看这个表的权限,你是会告诉他字段不对还是没权限?如果告诉他字段不对,其实给的信息太多了,因为没权限的意思还包含了:没权限知道字段是否存在

  2. 在缓存开启状态下, 要判别sql是select还是其他类型,保证只有select才去查询缓存,那么这个判断操作是何时进行的呢?
    实际上肯定是要判断出是select语句, 但是之后的解析都没做哈。 要理解成“包含在内”也可以

  3. 在mysql中通过 explain extendedshow warnings 命令来查看的sql, 是不是优化器重写之后的sql?
    show wanings不会把重写后的显示出来,只是格式化后

@git-zjx git-zjx added this to MySQL实战45讲 in MySQL Jul 11, 2019

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
1 participant
You can’t perform that action at this time.