查询就是用通过数据库规定的语法编写一条SQL,再通过数据库的逻辑处理,然后匹配出相应的数据信息;
语法我们知道,所以想知道SQL执行的原理就需要知道数据库的逻辑和架构,先看数据库的架构。
MySQL数据库的架构
首先先看架构图(link:01 | 基础架构:一条SQL查询语句是如何执行的? (geekbang.org))
MySQL数据库的架构主要包含两个模块,Service模块和存储模块,Service中包含连接器、分析器、缓存器(MySQL8.0版本去除了服务器端的缓存器模块)、优化器和执行器,Service模块是MySQL的主要业务模块
- 连接器是作为MySQL的入口,连接器负责跟客户端建立连接、获取权限、维持和管理连接,客户端如果太长时间没动静,连接器就会自动将它断开。这个时间是由参数 wait_timeout 控制的,默认值是 8 小时;
- 在这个模块会校验用户名和密码,不匹配会报错“Access denied for user”;
- 这个模块中会查询出用户权限,用户后期权限处理都会依照此处查询出来的权限;
- 分析器对SQL字符串进行解析,包括词法解析和语法解析,在这个模块中如果词法或语法错误,都会进行报错处理,同时表和表中列的对应也会在此处进行检查,如果列错误会报表中不存在列的异常;
- 缓存器故名思意就是对查询数据进行缓存,MySQL会将相同SQL的查询通过一个对大小写敏感的哈希查找实现的,当通过SQL进行查询的,会优先查询缓存器的数据,如果没有命中则会去查询分析器,走正常的查询流程;(在返回之前会校验权限)(MySQL8.0版本去除了服务器端的缓存器模块)
- 优化器对分析出的SQL进行优化处理,它会分析SQL不同执行方式,并选择出最优的执行方式,比如选择合适的索引或者选择合适的关联顺序;优化器阶段完成后,这个语句的执行方案就确定下来了;
- 执行器拿到优化器优化后的执行计划之后,首先会打开表,之后会调用表的引擎提供接口,引擎会一行一行的返回接口,最终执行计划统计的行数是执行器所扫描的行数,却不是数据扫描的行数,执行器调用一次,在引擎内部则扫描了多行,因此引擎扫描行数跟 rows_examined 并不是完全相同的。
SQL语句执行过程
介绍完架构,其实SQL的执行过程也已经清楚了,先通过
(1.连接器)连接,拿到相应的权限,然后
(2.缓存器)查找缓存,命中则直接返回,同时会进行表权限控制(在工程实现上,如果命中查询缓存,会在查询缓存返回结果的时候,做权限验证。查询也会在优化器之前调用 precheck 验证权限),如果没有命中,则会执行相应的查询过程,
(3.分析器)解释语句,分析词法和语法,同时会判断表、列和SQL的正确性
(4.优化器)优化语句,做索引优化,关联表优化
(5.执行器)执行语句,包括权限判断,打开表,通过存储引擎查询
备注
query_cache_type
查询缓存类型,有0、1、2三个取值:0则不使用查询缓存。1表示始终使用查询缓存。2表示按需使用查询缓存。
query_cache_size
默认情况下query_cache_size为0,表示为查询缓存预留的内存为0,则无法使用查询缓存。所以我们需要设置query_cache_size的值:
SET GLOBAL query_cache_size = 134217728;
注意上面的值如果设得太小不会生效。比如我用下面的SQL设置query_cache_size大小:
SET GLOBAL query_cache_size = 4000;