MYSQL(一)---基础架构(查询)
1.MYSQL(一)---基础架构(查询)
2.MYSQL(二)---日志系统(更新)
3.MYSQL(三)---事务隔离
学习MYSQL,不应该只是从简单的操作上去使用,学任何东西都需要从整体的架构去理解它的整体运行得原理。鸟瞰全貌,高纬度的去理解问题。
拿简单的sql来说:
select *from table_name where id=1
我们看到和使用的只是一条查询语句,然后返回得一个结果,就像程序运行得单线程一样,请求->响应,但是这条语句在MYSQL内部是如何执行的呢,就需要我们对MYSQL正义去解析了。
我们现在要做得就是把MYSQL进行拆解分析,通过对它的整体架构,进行块级分析,由这个拆解的过程中,对MYSQL进行更深层次的理解。
MYSQL分为Server层和存储引擎两部分
Server层包括连接器、查询缓存、分析器、优化器、等涵盖了Mysql大多的核心服务功能,以及所有得内置函数(日期、数据等),所有跨存储引擎的功能在这里进行实现,比如存储过程、触发器、视图等。
存储引擎层负责数据的存储和提取。它的架构模式是插件形式的,支持InnoDB\MyISAM、Memory等多种存储引擎。现在常用的是InnoDB(从5.5.5版本开始成为Mysql的默认储存引擎)。
在使用mysql得过程中,创建表creat table建表的时候,如果不指定引擎类型。默认使用后的就是InnoDB。在创建得过程中是可以指定引擎类型,不同的引擎支持的存取方式是不同的,支持的功能也是不同的。从上图中来看,不同的存储引擎使用的server层是共用的。这就需要我们对server层的功能流程进行理解。
连接器
在进行数据库的使用的过程中,首先进行就是连接数据库,连接器就是实现这个功能的。负责跟客户端建立连接、获取权限、维持和管理连接。连接命令:mysql -h$ip -P$port -u$user -p
,连接命令中的mysql是客户端工具,是用来和服务器建立连接。在完成TCP握手之后,连接器就开始认证身份,开始输入账号和密码。
- 如果用户名或者密码不对,就会收到报错,然后客户端程序执行结束
- 如果用户名、密码正确,连接器会在权限表里面查看用户的权限,之后的判断逻辑,都会依赖这个权限。
在用户进行连接之后,权限已经生成,如果此时用管理员账户对用户的权限进行了修改,也不会影响已经建立的链接的权限,只有重新进行连接后的权限改变。
客户端进行连接后,长时间没有进行操作,连接器会自动将它断开,这个时间是由参数wait_tiomeout控制的,默认得时间是8小时。如果断开之后,再次发送请求,就会收到错误:Lost connection to MySQL server during query。这时候需要继续的话,就要进行重连,然后再执行请求。
数据库长连接是指连接成功后,如果客户端有持续的请求,则使用同一连接。短链接是使用几次之后就断开,下次查询再重新建立一个。建立连接是一个复杂的过程,所以建议一般尽量减少建立连接的动作,尽量使用长连接。
但是使用长连接后,你就会发现,有时候mysql占用的内存就会涨的特别快,这是因为在长连接的过程中临时使用的内存是管理在连接对象里面的。这些对象会在连接断开的时候进行释放。所以长连接会累积下来,导致内存过大,被系统进行杀掉。这也是MySQL异常重启的原因之一。
长连接空闲断开解决办法:
1.定期断开连接。使用一段时间后或者程序里执行一个占用内存大的查询后,进行断开重连
2.如果使用的是5.7以后的版本,可以在每次执行一个比较大的操作后,通过执行mysql_reset_connection来重新初始化连接资源,这个过程不需要进行重新连接和权限认证,但是连接状态会恢复到刚刚创建得状态。
查询缓存
建立过连接之后,就可以执行select语句进行查询了,执行就会来到第二步逻辑,查询缓存。
MySQL拿到一个查询后,会先到查询缓存看看,是不是之前执行过这条语句。之前执行过的语句及其结果可能会以key-value形式换存在内存中,如果查询语句能够在key中找到,那么就会将value直接返回给客户端。
如果不在,将会进行后续的查询结果,执行后,执行结果会放到缓存中,这样如果直接命中缓存的话,查询的效率的确会很高。但是大多数情况下缓存的存在是弊大于利。
因为缓存的时效是经常存在的,只要对表有一个更新,这个表的缓存就会清空,同时缓存时效。废了很大劲存起来的缓存,还没有用就失效了,这不就很难受了吗。所以对于业务逻辑更新频繁的表,缓存是累赘。除非有一些静态表,比如系统配置什么的。
同时MySQL支持不使用缓存的配置,将query_cache_type设置成DEMAND,这样在执行sql得过程中,默认不使用缓存,如果需要使用的话,SQL_CACHE配置 :select SQL_CACHE * from table_name where ID=1;
(8.0之后的MySQL查询缓存的功能已经删除)
分析器
以上,如果没有命中缓存的话,现在就是要进行正规的查询操作了。
首先MySQL需要知道你需要进行什么操作,就是这里对语句进行分析。分析器的'词法分析',输入的sql一堆字符串和空格,需要识别这里面的意思。
select SQL_CACHE * from table_name where ID=1
首先执行select是一个查询语句,
"table_name "是表名,
"ID"是列ID
之后,就需要判断输入的语法是否正确,如果输入的不对就会收到错误提示,比如select输入错误,selext得话就会报错。
优化器
经过了上边的分析器进行语句分析之后,就需要让它去选择怎样去执行这条语句,决定使用哪个索引,使用多表关联的是偶,决定各表的连接顺序:select * from t1 join t2 using(ID) where t1.c=10 and t2.d=20;
- 既可以先从表t1里面取出c=10的记录的ID值,再根据ID值关联到表t2,再判断t2里面d的值是否等于20。
- 也可以先从表t2里面取出d=20的记录的ID值,再根据ID值关联到t1,再判断t1里面c的值是否等于10。
这两种执行方法的逻辑结果是一样的,但是执行的效率会有不同,而优化器的作用就是决定选择使用哪一个方案。
执行器
MySQL通过分析器知道了你要做什么,通过优化器知道了该怎么做,于是就进入了执行器阶段,开始执行语句。
开始执行的时候,要先判断一下你对这个表T有没有执行查询的权限,如果没有,就会返回没有权限的错误。
如果有权限,就打开表继续执行。打开表的时候,执行器就会根据表的引擎定义,去使用这个引擎提供的接口。
比如我们这个例子中的表T中,ID字段没有索引,那么执行器的执行流程是这样的:
1.调用InnoDB引擎接口取这个表的第一行,判断ID值是不是10,如果不是则跳过,如果是则将这行存在结果集中;
2.调用引擎接口取“下一行”,重复相同的判断逻辑,直到取到这个表的最后一行。
3.执行器将上述遍历过程中所有满足条件的行组成的记录集作为结果集返回给客户端。
至此,这个语句就执行完成了。
对于有索引的表,执行的逻辑也差不多。第一次调用的是“取满足条件的第一行”这个接口,之后循环取“满足条件的下一行”这个接口,这些接口都是引擎中已经定义好的。
你会在数据库的慢查询日志中看到一个rows_examined的字段,表示这个语句执行过程中扫描了多少行。这个值就是在执行器每次调用引擎获取数据行的时候累加的。