对于数据库的认识,相信很大一部分人像我一样只停留在写各种SQL、优化各种查询语句以及索引的建立之上,只是停留在“会用”的基础上。但是如果想要充分发挥MySQL的性能,就必须要了解其作为最流行的关系型数据库背后的各种优秀设计思想和特点,只有这样才能更好的使用它。
目前最普遍的认识是将MySQL分为三层,正如标题所写的连接认证,解析优化和存储引擎。每一层的作用各不相同,但是各个之间是相互协同,相互依存的关系。可以先看下图的各个组件协同工作的架构图,然后再来深入分析各层之间的作用。
这一层提供的服务并不是MySQL所独有的,大多数基于网络的客户端/服务器的工具或服务都有类似的架构,所以参考这些架构,就可以清楚的了解到在这层MySQL的作用——连接处理、授权认证等。
对于连接,并不是每一个客户端连接成功后服务器会创建一个新的线程,用完则销毁。事实上,服务端会提前帮我们缓存一部分线程,并不需要频繁的去创建或销毁线程。而且这个参数也是可以通过配置文件thread_cache_size参数来控制线程的数量。当一个客户端连接成功后会由服务器分配一个线程给这个客户端,这个客户端连接的查询只会在分配的这个线程中单独使用。
授权认证是指当一个客户端或者应用连接到MySQL服务器时,服务器会先对其进行身份的认证,认证的方式最普遍的就是使用用户名+主机地址+密码的方式进行认证。当然也有通过证书进行认证连接,如下图的Navicat连接MySQL所示。
认证完成以后,并不是你就能进入到下一步的操作,此时服务器仍然会继续进行校验,即对客户端提交的语句验证该客户端是否具有执行该语句的权限,例如是否允许对数据库(mysql)中的表(user)执行select语句的权限。
这一层可以说是MySQL的核心服务,因为在这一层中MySQL主要做的就是查询解析、分析、优化、缓存以及内置函数(日期、时间)等。而且涉及到跨存储引擎的功能(存储过程、触发器、试图)也是在这一层实现的。
一条查询语句的执行,首先服务器会去缓存中查询,如果能够找到对应的查询,服务器就不必再执行查询解析、优化和执行的整个过程,而是直接返回查询缓存中的结果集。反之,下一步就会进行SQL解析。MySQL在解析查询的同时,会创建内部的解析树,然后对其进行各种优化,包括重写查询、决定表的读取顺序以及选择合适的索引等。当然我们也可以通过特殊的关键字来提示优化器,人为影响它的决策过程,例如关键词STRAIGHT_JOIN、HIGH_PRIORITY等。当然我们也可以通过关键词来查看优化器解释(explain)优化过程的各个因素,从而知道如何进行优化决策,并提供一个参考的基准,便于用户重构查询和schema或者修改相关配置。
在优化过程中,优化器并不会关心表是使用的什么存储引擎,但是存储引擎对于优化查询是存在影响的。优化器请求存储引擎提供容量或某个具体操作的开销信息,以及表数据的统计信息等。例如,某些存储引擎的某种索引,可能对一些特定的查询有优化。
存储引擎主要是负责MySQL中数据的存储和提取,采用的方式与文件系统管理的方式是大同小异的。MySQL会将每个数据库(schema)保存为数据目录下的一个子目录,创建表时,MySQL会在这个子目录下创建一个与表同名的.frm文件来保存表的定义,因此我们在学习的MySQL就知道MySQL中表的大小写在不同的系统上(Windows和Linux)是有区别的,这一切都是因为MySQL使用文件系统的目录和文件来保存数据库和表的定义。通过命令show variables like 'datadir'可以查看这些文件的存储地址。
对于不同的存储引擎在保存数据和索引的方式是不同的,但是表的定义这些都是在MySQL服务层同一处理的,即在上面的第二层实现。可以通过命令show table status命令查看表的相关具体信息。具体的就不展开说明,只说明其中几个重要的。Engine是指明存储引擎的类型,这里默认的是使用InnoDB。Row_format是行的格式,可选项是Dynamic(行长度可变,包含可变长度字段,如VARCHAR2或BLOB)、Fixed(行长度固定的)、Compressed(只在压缩表中存在)。
InnoDB是MySQL 5.1后默认的存储引擎,之前是MyISAM。InnoDB有一个非常大的特点就是默认支持事务,它被设计来处理大量的短期事务。InnoDB的数据是存储在表空间中,也就是一系列的数据文件中(ibdata)。
InnoDB采用MVCC来支持高并发,并且实现了四个标准的隔离级别。其默认级别是可重复读(Repeatable Read),并且通过间隙锁策略防止幻读的出现。间隙锁使得InnoDB不仅仅锁定查询涉及的行,还会多索引中的间隙进行锁定,以防止幻影行的插入。
MyISAM提供了大量的特性,包括全文索引、压缩、空间函数等,但是唯一的缺点就是不支持事务和行级锁。MyISAM会将表存储在两个文件中:数据文件和索引文件,分别以.MYD和.MYI为扩展名。在上面我们说过Row_format这个表属性,MyISAM会根据表的定义来决定哪种方式,MyISAM表可以存储的行记录数一般受限于可用的磁盘空间或操作系统中单个文件的最大尺寸。在MySQL5.0中,MyISAM表如果是变长行,则默认配置只能处理256TB的数据,因为指向数据记录的指针长度是6个字节。而早版本中,指针长度默认是4字节,所以只能处理4GB的数据。
在上面的Row_format中的Compressed是针对与MyISAM,此类表数据在创建并导入以后,不会再进行修改操作,这就非常适合此种存储引擎。使用方式是使用myisampack对MyISAM表进行压缩。压缩表是不能进行修改的(除非先将表接触压缩,修改数据,然后再次压缩)。压缩表可以极大地减少磁盘空间占用,因此可以减少磁盘I/O,从而提升查询性能。
这种存储引擎只支持Insert和Select操作,这就非常适合记录日志型应用的。Archive引擎会缓存所有的写并利用zlib对插入的行进行压缩,所以比MyISAM表的磁盘I/O更少。但是每次Select查询都需要执行全表扫描。所以Archive类适合日志和数据采集类引用。
另外Archive支持行级锁和专用的缓冲区,所以可以实现高并发的插入。在一个查询开始直到返回表中存在的所有行数之前,Archive引擎会阻止其他的Select执行,以实现一致性读。另外也实现了在批量插入在完成之前对读操作是不可见的。
虽然存储引擎的种类有很多,但是服务器通过API与存储引擎进行通信,这些API屏蔽了不同存储引擎之间的差异,而且API包含了几十个底层函数,用于执行开始一个事务、根据主键提取一行记录的这些操作。存储引擎本身不会去解析SQL,而且不同存储引擎之间也不会进行通信,只是简单地响应上层服务器的请求。