为了了解这个问题,先从 Mysql 的架构说起,对于 Mysql 来说,大抵能够分为 3 层架构。
第一层作为客户端和服务端的连贯,连接器负责解决和客户端的连贯,还有一些权限认证之类。比方客户端通用用户名明码连贯到 Mysql 服务器,还有对于数据库表的执行权限。
第二层是核心层,基本上 Mysql 大部分的外围性能都在这一层,包含查问缓存、解析器、优化器之类,比方 SQL 解析、优化、索引抉择,到最初生成执行打算。
第三层则是存储引擎了,Mysql 通过执行引擎间接调用存储引擎 API 查询数据库中数据。
通过 Mysql 的架构分层,咱们首先就能够很清晰的理解到一个 SQL 的大略的执行过程。
- 首先客户端发送申请到服务端,建设连贯。
- 服务端先看下查问缓存是否命中,命中就间接返回,否则持续往下执行。
- 接着来到解析器,进行语法分析,一些零碎关键字校验,校验语法是否合规。
- 而后优化器进行 SQL 优化,比方怎么抉择索引之类,而后生成执行打算。
- 最初执行引擎调用存储引擎 API 查问数据,返回后果。
这就是一个很概括性的 SQL 执行过程,接下来,具体到每个步骤具体阐明一下。
查问缓存
如果你翻看 Mysql 的官网文档就会晓得,查问缓存在 5.7.20 版本曾经被弃用,并且 8.0 的版本曾经删除了。为啥要删除,可能感觉太鸡肋了吧。
咱们能够通过命令来查看查问缓存是否可用。
mysql> SHOW VARIABLES LIKE 'have_query_cache';
+------------------+-------+
| Variable_name | Value |
+------------------+-------+
| have_query_cache | YES |
+------------------+-------+
除此之外,查问缓存还有一些外围参数。更具体的阐明能够参考官网文档。
query_cache_type:是否关上查问缓存,值为 0\1\2,别离对应为 OFF\ON\DEMAND,ON 的话则代表开启查问缓存,然而能够通过 SELECT SQL_NO_CACHE
来手动禁用,DEMAND 则代表只缓存以 SELECT SQL_CACHE
结尾的 SQL 语句。
query_cache_limit:缓存后果大小限度,如果查问后果超过大小则不会被缓存,默认是 1M 大小。
query_cache_size:为查问缓存调配的内存大小,他是 1024 的整数倍。
query_cache_min_res_unit:查问缓存分配内存块的最小单位,默认为 4KB。这是查问缓存分配内存的根本单位,即使比方查问的数据只有 1 个字节,也会依照最小内存单元大小来分配内存空间。
在进行 SQL 解析之前,零碎会判断查问缓存是否关上,如果关上,就拿缓存中的查问和传入的查问比拟,如果齐全一样,就会从缓存中间接返回。
然而须要特地留神的是,无论大小写、空格还是正文,都会影响缓存的命中后果,也就是说必须齐全一样!
比方以下的 SQL 大小写不同、多了空格都无奈命中查问缓存。
select * from user;
SELECT * from user;
select * from user;
解析器 & 预处理器
如果查问缓存未命中,就会进入失常的 SQL 执行环节。
首先就像咱们失常的业务开发一样,第一步都是对参数的规定校验,Mysql 也一样,解析器会进行词法语法分析,基于语法规定对 SQL 进行校验。
比方关键字是否应用正确啊,或者说关键字程序是不是正确,比如说你把 select
写成了 selct
,order by
写成了by order
。
如果校验 OK,那么就生成一颗“解析树”。
接着预处理器就是进一步根据非法规定生成的解析树进行校验,比方表名、列名是否存在等等。
优化器
如果说解析器和预处理器是咱们业务逻辑的前置校验环节,优化器就是真正的解决业务逻辑的中央。
一条查问 SQL 能够有 N 种执行形式,优化器的最终目标是找到最好的执行打算,交给执行引擎去执行。
然而理论应用中咱们常常会发现,Mysql 常常有抉择错索引的状况,我明明有更快的索引,后果它不必,导致搞出了慢查问。
这是因为 Mysql 的优化器是基于老本模型的优化器,他只是基于已有的老本计算公式来抉择一个老本最低的执行形式,这个执行形式不肯定会是最快的,只能说大多数时候,优化器的抉择比咱们本人的抉择更精确。
总的来说,这个优化过程太简单了,流程大抵就是下图所示,更具体的内容能够看《数据库查问优化器的艺术原理解析与 SQL 性能》这本书(我切实是懒得看了,吐了)。
执行引擎
大部分外围的事件曾经被优化器解决完了,最初执行引擎只有依据生成好的执行打算查问数据返回就好了,这一步绝对就挺简略了。
执行引擎只须要依据执行打算的指令调用存储引擎的 API 就能够了。
当然这一步如果能够缓存查问后果,那么就在这个阶段把查问后果缓存下来,而后把后果返回给客户端就能够了。
总结
一图胜千言。