步步深入MySQL:架构->查询执行流程->SQL解析顺序
一、前言
我长久以来都渴望了解一条SQL语句是如何被运行的,它的执行流程又是如何排列的,经过查阅和整理了大量的资料,最终撰写成了这篇博文。
本文将围绕MySQL的整体架构,深入解析其查询执行流程,并详细阐述语句的执行顺序,以探讨相关知识点。
二、MySQL架构总览
架构最好看图,再配上必要的说明文字。
下图根据参考书籍中一图为原本,再在其上添加上了自己的理解。
观察上图,我们发现该架构共分为两个层级,位于上方的是名为“SQL Layer”的MySQLD层,下方则是提供接口的多种存储引擎,统称为“Storage Engine Layer”。其余各个模块与组件,仅从名称即可直观地知晓其功能,故此处不再赘述。
三、查询执行流程
继续前行一段距离,让我依据个人理解,简要阐述一下查询操作的具体步骤流程。
1、连接
客户端发送一条查询请求,同时等待其“连接管理模块”对请求进行接收处理。
1.2、将请求转发到‘连接进/线程模块’;
1.3、调用‘用户模块’来进行授权检查;
经过检查确认后,系统将‘连接进/线程模块’从‘线程连接池’中挑选出可用的空闲连接线程步步深入MySQL:架构->查询执行流程->SQL解析顺序,并将其与客户端的请求进行匹配对接;若对接过程中出现失败,系统将启动创建新的连接请求的流程。
2、处理
首先,对缓存进行检索,确认Query语句是否完全吻合,随后,进一步核实权限是否具备,若这两项检查均顺利通过,便直接提取数据并予以返回。
若前一步骤出现失误,则需将任务移交至“命令解析器”,随后进行词汇分析和语法分析,最终构建出解析树。
在接下来的预处理环节,我们将对解析器无法解析的语义进行操作,同时进行权限审核,并据此构建新的解析树。
2.4、再转交给对应的模块处理;
在执行SELECT查询时,系统会经过“查询优化器”进行大量的优化处理,并据此生成相应的执行计划。
模块在接收到请求信息后,会利用‘访问控制模块’对连接的用户进行权限审核,确保其是否具备对目标表和特定字段的访问权利。
2.7、需调用“表管理模块”,首先检查table cache中是否已有记录,若存在,则直接定位至相应表并获取锁;若不存在,则需重新打开表文件。
依据表格的元信息,提取该表的存储引擎种类及相关细节,并借助接口功能对相应的存储引擎进行操作处理。
在上述流程中,一旦数据发生变动,若启用日志记录功能,相关信息便会自动被存入对应的二进制日志文件里。
3、结果
在Query请求处理完毕后,我们需要将所得的结果集传递给‘连接进/线程模块’。
3.2、返回的也可以是相应的状态标识sql外连接执行顺序,如成功或失败等;
对“连接进/线程模块”执行后续的清理任务,同时保持对请求的持续等待或与客户端的连接断开。
4、一图小总结
四、SQL解析顺序
接下来再走一步,让我们看看一条SQL语句的前世今生。
首先看一下示例语句:
然而它的执行顺序是这样的:
尽管事先未曾料到会是这种情形,但仔细观察后,仍觉得其显得相当自然且协调;究竟是从何处获取这些信息,还需不断调整筛选条件,决定是选取相同还是不同的内容,并对它们进行排序,这才明白需要提取哪些前几项数据。
既然如此了,那就让我们一步步来看看其中的细节吧。
1、准备工作
1.1、创建测试数据库
1.2、创建测试表
1.3、插入数据
1.4、最后想要的结果
现在开始SQL解析之旅吧!
2、FROM
在处理多个表格信息时,左侧表格的输出结果将直接成为右侧表格的输入数据,随后将构建出一个名为VT1的虚拟表格。
2.1、(1-J1)笛卡尔积
对两个存在关联关系的表格进行笛卡尔积运算,从而构建一个名为VT1-J1的虚拟表格。
2.2、(1-J2)ON过滤
以虚拟表VT1-J1为基础进行筛选,筛选出符合ON谓词要求的各项,进而构建出新的虚拟表VT1-J2。
请注意:鉴于语法限制,此处采用了“WHERE”一词,读者亦能从中体会到两者之间细微的联系。
2.3、(1-J3)添加外部列
若采用外连接(LEFT,RIGHT,FULL)方式,即便主表(即保留表)中存在不满足ON条件的列,这些列仍会被纳入VT1-J2,充当外部行,进而形成虚拟表VT1-J3。
我在网络上发现了一张描绘“SQL连接”概念的生动图表,若此图触犯了您的权利,恳请您告知以便我将其移除,在此先表谢意。
2、WHERE
在VT1处理流程中,需对所创建的临时表格进行筛选,确保WHERE子句中指定的列数据被成功导入至VT2表格中。
注意:
此刻,由于分组限制,我们无法执行聚合操作;同时,在SELECT语句中定义的别名也无法使用。
与ON的区别:
若存在外部关联列,在执行ON过滤操作时,所针对的是关联的表格,而主表(即保留的表格)则会输出所有列的信息。
如果没有添加外部列,两者的效果是一样的;
应用:
对主表的过滤应该放在WHERE;
在处理关联表时,若先执行条件查询再进行连接操作,应使用ON关键字;而若先进行连接操作,再执行条件查询,则需使用WHERE子句。
3、GROUP BY
该子句负责将VT2生成的表格依据GROUP BY子句指定的列进行分类,进而形成VT3表格。
注意:
在后续处理流程中,若涉及SELECT或HAVING关键字,所引用的列名需包含在GROUP BY子句中;若GROUP BY中未提及,则必须通过聚合函数进行引用。
原因:
GROUP BY修改了表的引用方式sql外连接执行顺序,将其转变为一种新的引用形式,这样做会导致可用于进行下一级逻辑操作的列数量相应减少。
我的理解是:
依据分组标准,将相同分组标识的资料合并为单一数据条目,鉴于每个分组仅能输出一条信息,除非该信息因过滤条件未被包含在内。对于那些在分组字段之外可能存在多个不同值的字段,这些多值信息无法整合进单一记录中,因此需借助聚合操作,将这些多值字段转化为单一值。
4、HAVING
该子句针对VT3表中的不同分组进行筛选,仅对分组后的数据进行操作,符合HAVING条件的子句会被纳入VT4表中。
5、SELECT
这个子句对SELECT子句中的元素进行处理,生成VT5表。
对SELECT子句内的表达式进行运算,进而生成VT5-J1。
(5-J2)DISTINCT
寻找VT5-1中的重复列,并删掉,生成VT5-J2
若在查询时加入了DISTINCT子句,系统便会生成一个临时的内存表格(若内存空间不足,则需转存至硬盘)。此临时表的结构与之前生成的虚拟表VT5保持一致,但新增了对参与DISTINCT操作的列的唯一索引,目的在于剔除重复信息。
6、ORDER BY
在VT5-J2的表格中步步深入MySQL:架构->查询执行流程->SQL解析顺序,依据ORDER BY子句的指定条件,对数据进行了排列,最终生成了VT6的新表。
注意:
唯一可使用SELECT中别名的地方;
7、LIMIT
LIMIT子句负责从前一步骤生成的VT6虚拟表中提取特定位置起至指定行数的记录。
注意:
offset和rows的正负带来的影响;
当偏移量很大时效率是很低的,可以这么做:
通过子查询进行优化处理,首先在子查询中从索引中提取出最大的ID值,接着以倒序的方式排列,最后选取前N行作为结果集。
通过INNER JOIN进行优化处理,在JOIN子句中,优先从索引中提取ID列表sql外连接执行顺序,进而直接进行查询操作,以获取最终的查询结果。
至此SQL的解析之旅就结束了,上图总结一下:
- 随机文章
- 热门文章
- 热评文章