目录
执行sql语句的时候MySQL发生了什么
在初学MySQL的时候,我们一定会写道这样的一句sql语句
//在T表中查询id = 1的语句 select *from T where id = 1;
虽然知道这条语句是用来查询指定的数据的,但是期间,MySQL发生了什么?
首先我们先来来了解一下MySQL的架构
可以看出来MySQL主要分为server层和存储引擎层
- server层主要用于建立连接,对sql语句的分析和执行。server层有MySQL的大多数核心模块。还有一些内置函数(日期、时间、数学和加密函数等)和所有跨存储引擎的功能(如存储过程、触发器、视图等。)都在 Server 层实现。
- 存储引擎层主要是负责数据的存储和数据的读写操作。但是不同的存储引擎内支持的索引类型不同,如InnoDB默认的是B+树,默认也是B+树。
了解了mysql的整体架构,接下来我们来继续细致的了解具体每个功能模块的作用
第一步连接器
连接器的作用是让MySQL与客户端进行连接,这个语法是
mysql -h$ip -u$user -p
- -h是MySQL要服务的IP地址,如果你是本地连接,则这个参数可以省略
- -u是指定用户,一般为管理员root
- -p后面接的是你的MySQL登录密码。但是不建议在这后面写密码,这样密码不安全,最好是在命令行交互的时候填写密码
MySQL是采用TCP协议的,经过三次握手之后,开始认证你的身份,这时候需要你输入你的登录用户名和密码
- 如果用户名或密码不对,你就会收到一个"Access denied for user"的错误,然后客户端程序
结束执行。
- 如果用户名密码认证通过,连接器会到权限表里面查出你拥有的权限。之后,这个连接里面
的权限判断逻辑,都将依赖于此时读到的权限
所以当一个用户成功连接了数据库之后,即使管理者对这个用户的权限进行修改,也不影响这次登录的权限。
登录之后,可以使用show processlist;命令来查询连接状态 Query指的是连接状态,如果是sleep则是休眠状态,没有产生连接。
空闲连接会一直被占用吗?
当然不是。如果以一个连接长时间没有动静,默认状态下,8个小时就断开连接,我们可以使用show variables like 'wait_timeout';命令查看wait_timeout最长空闲连接时间
当然我们也可以手动断开连接,使用 kill connection + id 命令,id是how processlist;命令时查询到的id
mysql在连接的时候有长连接与短连接之分
- 长连接,可以执行很多个sql不断开连接
- 短连接,在执行了几个sql时会发生断开,下次查询时,在创建一个连接
创建连接通常比较复杂,所以一般情况下会使用长连接。但是如果一个长连接长时间不断开,会占用许多的内存。
如何解决占用大量内存的情况
- 定时断开连接。在长时间使用长连接时,或者MySQL执行了一个比较大的操作之后,就断开连接重新创建连接。
- 客户端主动重置连接。MySQL 5.7 版本实现了 mysql_reset_connection() 函数的接口,注意这是接口函数不是命令,那么当客户端执行了一个很大的操作后,在代码里调用 mysql_reset_connection 函数来重置连接,达到释放内存的效果
第二步查询缓存
在建立完成之后,就会来到第二步,查询缓存。
在每条命令执行之前,都会先进行查询缓存,查看之前是否运行过这个命令,如果运行过的话,就直接返回结果,因为执行过的语句会以key-value的形式被缓存,sql语句是key,值是value。不用进行下面的分析器,优化器和执行器,直接返回结果,提高效率。
但是我们一般不使用查询缓存,你知道为什么吗?
听起来查询缓存的效率非常的高,其实查询缓存特别的鸡肋。
因为如果一张表的数据需要更新,那么整张表就会被清空,所以查询缓存的效率确实非常的低。
在mysql8.0版本查询缓存功能已经被删除了,但是如果你使用的8.0之前的版本,可以通过将参数 query_cache_type 设置成 DEMAND,来关闭查询缓存。
第三步分析器
sql语句进入分析器时,会做两件事
- 第一件事情,词法分析。MySQL 会根据你输入的字符串识别出关键字出来,构建出 SQL 语法树,
这样方便后面模块获取 SQL 类型、表名、字段名、 where 条件等等。
- 第二件事情,语法分析。根据词法分析的结果,语法解析器会根据语法规则,判断你输入的这个
SQL 语句是否满足 MySQL 语法。
第四步优化器
优化器的作用是在执sql语句时,选择哪条索引。
如果有一条这样的sql语句
select *from T1 join T2 where T1.id = 10 and T2.id = 20;
在执行这条语句时,mysql将要选择选
- 用既可以先从表T1里面取出id=10的记录值,再关联到表T2,再判断T2里面id的值是 否等于20。
- 也可以先从表T2里面取出id=20的记录值,再关联到T1,再判断T1里面id的值是否等于10。\
这两个方案的结果是一样的,但是效率不同,mysql会选择最优方案执行这条sql语句。
第五步执行器
上面的步骤都执行完全之后,就会来到执行器,mysql开始真正执行语句。执行器会开始与存储引擎交互。MySQL会检查用户对这条语句有没有执行权限,如果有就继续往下执行。执行步骤如下
1. 调用InnoDB引擎接口取这个表的第一行,判断ID值是不是10,如果不是则跳过,如果是则
将这行存在结果集中;
2. 调用引擎接口取“下一行”,重复相同的判断逻辑,直到取到这个表的最后一行。
3. 执行器将上述遍历过程中所有满足条件的行组成的记录集作为结果集返回给客户端。
到这里,整条sql语句才执行完。