总体架构
先看下总体架构,有一个全览的概念。
连接
MySQL服务监听的端口默认是3306,客户端连接的方式也有很多。可以是同步的也可以是异步的,可以是长连接也可以是短连接,可以是TCP连接也可以是Unix Socket,MySQL有专门处理连接的模块,连接的时候需要验证权限。
客户端每产生一个连接或者一个会话,在服务端就会创建一个线程来处理。反过来,如果要杀死会话的话,就是kill掉线程。 我们用show processlist看下有哪些连接,kill 的时候就是 kill 下面的 id。
如果客户端太久没动静,连接器会把那些长时间不活动的sleep连接断开,有两个参数wait_timeout和interactive_timeout,默认都是28800,即8小时。
如果在连接被断开之后,客户端再次发送请求的话,就会收到一个错误提醒: Lost connection to MySQL server during query。 这时候如果你要继续,就需要重连,然后再执行请求了。
既然连接消耗资源,会创建线程,那也不能让你无限制的连,所以有个参数控制你的最大连接数,在5.7版本中默认是151个,最大可以设置成100000。
查询缓存
MySQL内部自带了一个缓存模块,我们看下缓存默认是关闭着的。
那既然有这个模块干嘛要关着呢,主要是因为MySQL自带的缓存的应用场景有限,第一是它要求SQL语句必须一模一样,中间多一个空格,字母大小写不同都被认为是不同的SQL。 第二是表里面任何一条数据发生变化的时候,这张表所有缓存都会失效,所以对于有大量数据更新的应用,也不适合。 所以缓存这一块,我们还是交给ORM框架,比如MyBatis默认开启了一级缓存,或者独立的缓存服务器,比如Redis。在MySQL8.0开始,查询缓存功能已经被移除了。
解析器和预处理器
解析器Parser和预处理器Preprocessor,这一步主要对SQL语句进行词法和语法分析和语义的解析。
词法分析
词法分析就是你输入的是由多个字符串和空格组成的一条 SQL 语句,MySQL 需要识别出里面的字符串分别是什么,代表什么。MySQL 从你输入的"select"这个关键字识别出来,这是一个查询语句。它也要把字符串“T”识别成“表名 T”,把字符串“ID”识别成“列 ID”。
select name from user_innodb where id=1;
比如这句sql会被打破成8个单词。
语法分析
第二步就是语法分析,语法分析会对SQL做一些语法检查,比如单引号有没有闭合,然后根据MySQL定义的语法规则,根据SQL语句生成一个数据结构。这个数据结构我们把它叫做解析树(select_lex) 。
如果你的语句不对,就会收到“You have an error in your SQL syntax”的错误提醒,比如下面这个语句 select 少打了开头的字母“s”。
预处理器
如果词法和语法都正确,但是字段名或者表名不存在 ,这时候会在哪里报错,对,就是预处理器。
预处理器进一步检查解析树的合法。比如: 数据表和数据列是否存在, 别名是否有歧义等。如果通过则生成新的解析树,再提交给优化器。
优化器
在开始执行之前,还要先经过优化器的处理。一条SQL语句是可以有很多执行方式的,最终返回相同的结果,他们是等价的。查询优化器的目的就是根据解析树生成不同的执行计划,然后选择一种最优的执行计划,MySQL里面使用的是基于开销(cost)的优化器,哪种执行计划开销最小,就用哪个。
优化器会优化一些比如当我们对多张表关联查询的时候,以哪个表的数据为基准表;当有多个索引可以使用的时候,选择哪个索引。 但是优化器也不是万能的,并不是再垃圾的SQL语句都能自动优化,也不是每次都能选择到最优的执行计划,大家在编写SQL的时候还是要注意。
优化器完成以后,会把解析树变成一个查询执行计划,查询执行计划是一个数据结构。 我们在SQL语句前面加上explain就可以看到执行计划信息。
explain select * from user_innodb where id=1;
如果要看到详细的信息,还可以用format=json,或者开启optimizer trace。
explain format=json select * from user_innodb where id=1;
执行器
执行器开始执行的时候,要先判断一下你对这个表 T 有没有执行查询的权限,如果没有,就会返回没有权限的错误。
如果有权限,就打开表继续执行。执行器使用执行计划去操作存储引擎。它利用存储引擎提供的相应的API来完成操作。最后把数据返回给客户端。
存储引擎
存储引擎有很多,在navicat里面可以看到
创建表的时候也可以指定,现在最常用的存储引擎是 InnoDB,它从 MySQL 5.5.5 版本开始成为了默认存储引擎。当你执行 create table 建表的时候,如果不指定引擎类型,默认使用的就是InnoDB。
查看存放的目录
不同的存储引擎存放数据的文件也不一样,frm是表结构文件,数据文件innodb是一个,memory没有,myisam是两个。
常用存储类型比较,https://dev.mysql.com/doc/refman/5.7/en/storage-engines.html
MyISAM(3个文件)
应用范围比较小,表级别锁限制了读/写的性能,因此在web和数据仓库配置中,它通常用于只读或者以读为主的工作。
- 支持表级别的锁,插入和更新会锁表。不支持事务。
- 拥有较高的插入insert和查询select的速度。
- 存储了表的行数(count速度更快)。
如何快速向数据库插入100万条数据,我们可以先以MySIAM引擎插入数据,然后再将存储引擎修改为InnoDB。
InnoDB(2个文件)
mysql5.7里面默认的存储引擎。InnoDB是一个事务安全(与ACID兼容)的MySQL存储引擎,它具有提交、回滚和崩溃恢复功能来保护用户数据。 InnoDB行级锁(不升级为更粗粒度的锁)和Oracle风格的一致非锁读提高了多用户并发性和性能。InnoDB将用户数据存储在聚集索引中,以减少基于主键的常见查询的I/O。为了保持数据完整性,InnoDB还支持外键引用完整性约束。
- 支持事务,支持外键,因此数据的完整性、一致性更高。
- 支持行锁和表锁
- 支持读写并发,写不阻塞读(MVCC)
- 特殊的索引存放方式,可以减少IO,提升查询效率
适合经常更新的表,存放并发读写或者有事务处理的业务系统。
Memory(1个文件)
将所有数据存储在内存中,以便在需要快速查找非关键数据的环境中快速访问。这个引擎之前被成为堆引擎,其使用案例正在减少;InnoDB及其缓冲池内存区域提供了一种通用、持久的方法来将大部分或者所有数据保存在内存中,而ndbcluster为大型分布式数据集提供了快速的键值查找。
把数据放在内存中,读写的速度很快,但是数据库重启或者崩溃,数据会全部消失,只适合做临时表。
CSV(3个文件)
它的表实际上是带有逗号分隔值的文本文件。csv表允许以csv格式导入或者转储数据,以便与读写相同格式的脚本和应用程序交换数据。因为csv表没有索引,所以通常在正常操作期间将数据保存在innodb表中,并且只在导入或者导出阶段使用csv表。
不允许空行,不支持索引。格式通用,可以直接编辑,适合在不同数据库之间导入导出。
Archive(2个文件)
这些紧凑的未索引的表用于存储和检索大量很少引用的历史、存档或者安全审计信息。
不支持索引,不支持update、delete。
如何选择存储引擎
存储引擎有很多,不同的应用场景下选择不同的存储引擎。
- 如果对数据一致性要求比较高,需要事务支持,可以选择InnoDB。
- 如果数据查询多更新少,对查询性能要求比较高,可以选择MySIAM。
- 如果需要一个用于查询的临时表,可以选择Memory。
如果这些存储引擎不能满足你的需求,没关系,你还能自己开发一个存储引擎,https://dev.mysql.com/doc/internals/en/custom-engine.html ,按照这个开发规范,实现相应的接口,给执行器操作。之所以执行器能够执行所有的存储引擎,就是存储引擎都遵循了一套规范,提供了相同的操作接口。
MySQL体系总结
总体上我们可以把MySQL分成三层。
连接层
我们的客户端要连接到MySQL服务器3306端口,必须要跟服务端建立连接,那么管理所有的连接,验证客户端的身份和权限,这些功能就在连接层完成。
服务层
连接层会把SQL语句交给服务层,这里面又包含一系列的流程:
比如查询缓存的判断、根据SQL调用相应的接口,对我们的SQL语句进行词法和语法的解析(比如关键字怎么识别,别名怎么识别,语法有没有错误等等)。
然后就是优化器,MySQL底层会根据一定的规则对我们的SQL语句进行优化,最后再交给执行器去执行。
存储引擎
存储引擎就是我们的数据真正存放的地方,在MySQL里面支持不同的存储引擎,再往下就是内存或者磁盘。
最后感谢大家的观看~
|