SQL的解析和优化的原理:一条sql 执行过程是什么?

本文 的 原文 地址

本文 的 原文 地址

尼恩说在前面:

在40岁老架构师 尼恩的读者交流群(50+)中,最近有小伙伴拿到了一线互联网企业如得物、阿里、滴滴、极兔、有赞、shein 希音、shopee、百度、网易的面试资格,遇到很多很重要的面试题:

说说sql 解析和优化的 原理?

说说一条 sql从 SQL输入 到结果 返回的执行过程?

前几天 小伙伴面试 京东,遇到了这个问题。但是由于 没有回答好,导致面试挂了。

小伙伴面试完了之后,来求助尼恩。那么,遇到 这个问题,该如何才能回答得很漂亮,才能 让面试官刮目相看、口水直流。

所以,尼恩给大家做一下系统化、体系化的梳理,使得大家内力猛增,可以充分展示一下大家雄厚的 “技术肌肉”,让面试官爱到 “不能自已、口水直流”,然后实现”offer直提”。

当然,这道面试题,以及参考答案,也会收入咱们的 《尼恩Java面试宝典》V145版本PDF集群,供后面的小伙伴参考,提升大家的 3高 架构、设计、开发水平。

最新《尼恩 架构笔记》《尼恩高并发三部曲》《尼恩Java面试宝典》的PDF,请关注本公众号【技术自由圈】获取,后台回复:领电子书

一条 sql 执行总体过程

一条SQL语句的执行过程可以大致分为以下几个步骤:

Client层:接收用户输入的SQL,显示响应的结果

Server层:对SQL进行格式的校验、语言分析、优化和执行,并对执行结果进行返回

  • 连接器:用户的认证和授权,对接口进行链接
  • 缓存:对查询结果进行缓存,并在对缓存进行查询时返回命中结果
  • 分析器:SQL的词法分析和语法分析
  • 优化器:生成SQL执行计划,操作索引进行数据的查询
  • 执行器:SQL操作引擎(如innodb 引擎),利用文件系统返回查询结果

文件系统层:对数据进行持久化

MySql中SQL语句核心执行流程如下:

image-20250511081910500

Mysql中sql语句执行顺序全景图:

SQL输入 → 解析器(词法分析 → 语法分析 → 语义分析)→ AST → 预处理器(类似语义分析)→ 优化器(逻辑优化 → 物理优化) → 物理查询计划 → 执行引擎 → 结果返回

核心步骤如下:

  • **‌词法分析‌: **将SQL字符串拆解为原子单元(如关键字、表名、运算符等),生成Token序列
  • **‌语法分析‌:**验证Token组合是否符合SQL语法规则,构造抽象语法树(AST)描述查询结构
  • 预处理器 ,根据一些 mysql规则进一步检查解析树是否合法。
  • **‌逻辑优化:**优化查询语义(如重写子查询、消除冗余列),生成逻辑执行计划(Logical Plan)
  • **物理优化:**将逻辑计划映射到物理操作(如选择索引、Join算法、数据分片策略),生成物理执行计划
  • **‌执行代码‌:**编译器或引擎将物理计划转换为底层可执行指令(如机器码/字节码),驱动数据库完成计算并返回结果。

下面重点分析SQL的解析和优化过程,包括词法分析、语法分析、逻辑分析和物理分析。

第一:词法分析

SQL解析与优化本质上属于编译器技术的一部分,和C语言等其他编程语言的处理方式没有本质区别。

SQL解析与优化 整个过程主要包括几个步骤:

  • 词法分析 + 语法分析
  • 语义分析
  • 查询优化
  • 物理执行计划。

SQL解析的主要目的,是把用户输入的一条“字符串”形式的SQL语句,转换成一种结构化的表示方式(称为结构体),让数据库系统能够理解并执行这条语句。

这个过程包括三个主要阶段:词法分析、语法分析和生成抽象语法树。

什么是 词法分析器?

词法分析器相当于扫描仪(专业叫DFA),将一串原始的字符流拆分成一个个有意义的基本单元——称之为“标记”(token)。

它基于预定义的一些语法规则,识别出关键字、标识符、数字、运算符等内容。

比如,下面这条简单的SQL语句:

下面这条简单的SQL语句:


SELECT
  SALARY + 200
FROM
  T_EMPLOYEE
  

经过词法分析后会被拆分成如下几个标记:

  • 关键字:SELECT
  • 标识符:SALARY
  • 运算符:+
  • 数值:200
  • 关键字:FROM
  • 标识符:T_EMPLOYEE

每个单词都被贴上类型标签,形成规范的碎片化元素。

这个过程消除了注释、空格等无效信息,为后续语法分析准备好结构化的数据原料。

在 SQL 解析过程中,词法分析器 就是一个 确定有限自动机 (DFA),它的主要任务是将输入的字符集按照预定义的词法规则转换为“单词”(即标记,tokens)。

这些单词是后续语法分析的基础,过程中的输入和输出分别是

  • 输入:原始的字符流(如 SQL 语句)
  • 输出:结构化的标记流(如关键字、标识符、数字等)

什么是 DFA?

DFA(确定有限自动机):‌就是一套“输入→处理→输出”的流水线机器,它干活的方式特别简单粗暴,

比如SQL解析中,DFA就像个“拆词小能手”,把SELECT A FROM B拆成:【关键词SELECT】→【字段A】→【关键词FROM】→【表名B】,中间遇到不认识的符号直接报错,绝不瞎猜

第二:语法分析

在词法分析完成之后,下一步就是语法分析

什么是 语法分析 ?

sql解析执行包括了:词法分析,语法分析,分析机,生成语法树

img

词法分析:从左到右一个字符、一个字符地输入,然后根据构词规则识别单词。

将会生成Token词

词法分析 在进行了词法分析以后,他会把sql默认扫描成两个部分,一个是关键字(select,insert,from,where,group by …)一个是非关键字(查询的字段,查询的表,查询的筛选条件,分组条件)

语法分析,分析机:它们两个是一起工作的,它们对词法分析生成的Token词开始循环构造语法树,直到整个SQL语句扫描完成了,就构成了一棵语法树

语法分析 阶段会把词法分析生成的“单词”(也就是标记)作为输入,然后检查这些单词组合起来是否符合 SQL 的语法规则。

简单来说, 语法分析 要判断用户写的 SQL 语句是不是“结构正确”。

比如:

有这样一条语句:


SELECT SALARY + 100 FROM T_EMPLOYEE

语法分析器会认为这是合法的,因为它看起来结构完整:有查询字段、有表达式、也有数据来源(表名)。

但如果写成这样:


SELECT SALARY + 100 FROM

这就是一条不合法的语句,因为 FROM 后面没有指定表名,结构不完整。

这时候语法分析器就会报错,提示你缺少必要的内容。

总结: 语法判断的作用就是根据 SQL 的语法规范,判断用户写的语句是否格式正确,为后续处理打下基础。

语法分析的过程,就是 一步步构建出来 一科 抽象语法树(AST,全称 Abstract Syntax Tree) 。

img

值得注意的是,当SQL 关键字写错了,会在词法分析阶段报错,

比如,如果没有加上表名,或条件等格式错误了会在语法分析阶段报错

抽象语法树(AST)

抽象语法树(AST,全称 Abstract Syntax Tree)是用来表示用户输入的 SQL 语句的一种树状结构。

简单来说,它把一条 SQL 语句的“意思”用结构化的方式画成一棵树,每个节点代表一个词或一个操作,比如关键字、列名、表名、运算符等。

这棵 AST 树 是在语法分析过程中一步步构建出来的。

当语法分析顺利完成时,就会生成对应的抽象语法树。

这个树和用户输入的 SQL 是一一对应的,也就是说,输入的 SQL 字符串已经变成了数据库可以理解和处理的“结构体”。

举个简单的例子:原始 SQL 输入:


SELECT SALARY + 100 FROM T_EMPLOYEE

经过语法分析后,会生成一棵结构清晰的抽象语法树,树中包含以下信息:

  • 查询类型是 SELECT
  • 要查询的内容是 SALARY + 100(其中 SALARY 是字段名,+ 是运算符,100 是数值)
  • 数据来源是 T_EMPLOYEE

通过这棵 AST 树,数据库就能清楚地知道这条 SQL 到底要做什么,为后续的执行和优化打下基础。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

语法分析就是生成语法树的过程。这是整个解析过程中最精华,最复杂的部分。

这部分MySQL使用了Bison来完成。

如何设计合适的 AST 数据结构以及相关算法,去存储和遍历所有的信息,非常值得大家去理解,去研究。

再给个简单案例,SQL语句如下:


select username, ismale from userinfo where age > 20 and level > 5 and 1 = 1

会生成如下 AST 语法树。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

第三:预处理器 (类似语义分析)

预处理器 ,根据一些 mysql规则进一步检查解析树是否合法。

如检查查询的表名、列名是否正确,是否有表的权限

这一步操作目的是解决原来每一句sql都会单独解析执行的问题,后来变成了使用预处理器,对于相同的命令模板,不断的替换参数,减少对表权限和语法树是否合法的计算

生成命令模板:对于第一次进入的sql语句肯定是没有命令模板的,所以它需要参与生成命令模板 ,比如select id from student where id =1; 那么 “ select id from student where id = ” 就会成为模板

当模板生成了以后,对于student这个表,属性为id的字段,这个模板是已经检查过有没有权限的了,它在这个模板上都是有记录的

替换参数条件:这是对于有模板的情况下,我们就会直接使用参数替换的形式,把命令完成,比如这个时候有一条sql:select id from student where id = 100 ;很显然,上次我们已经生成过模板了,

就可以直接用,模板就是select id from student where id = 这个时候就只需要把参数替换掉,这次 id = 100;就把原来的 1 替换为100 ,

这样做的好处就是,不用再去检查语法树合不合法了,不用去看表是否有没有权限了,

因为在生成模板的时候这些操作都是做过的了,如果模板语法树不合法,拿这次的sql也不合法,如果模板没有student表的权限,那么这次也没有

极大避免了二次计算和操作,对性能的提升非常大

img

经过了预处理器以后,就拿到了这句sql是否有执行的权力,即能否更改表和查询表的权力,

如果权限没有问题,那么就可以进行下一步:SQL优化

第四:优化器(逻辑优化 → 物理优化)

接下来,就是结合 AST 语法树, 进行优化 。

当语法树被认为是合法的了,并且由优化器将其转化成执行计划。

一条查询可以有很多种执行方式,最后都返回相同的结果。

优化器的作用就是找到这其中最好的执行计划。

执行计划:mysql不会生成查询字节码来执行查询,mysql生成查询的一棵指令树,然后通过存储引擎执行完成这棵指令树并返回结果。

最终的执行计划包含了重构查询的全部信息。

查询的生命周期的下一步是将一个SQL转换成一个执行计划,mysql在依照这个执行计划和存储引擎进行交互。

这包含多个子阶段:解析SQL、预处理、优化SQL执行计划

这个过程中任何错误都可能终止查询。

  • 查询优化器:当语法树被认为是合法的了,并且由优化器将其转化成执行计划。一条查询可以有很多种执行方式,最后都返回相同的结果。优化器的作用就是找到这其中最好的执行计划。
  • 执行计划:mysql不会生成查询字节码来执行查询,mysql生成查询的一棵指令树,然后通过存储引擎执行完成这棵指令树并返回结果。最终的执行计划包含了重构查询的全部信息。

在优化器的内部,是开发者定义的许多“优化规则”来进行优化的,如关联查询重排,索引优选,连接查询重组,优化排序,优化聚合函数,提前终止查询,等价变化等;

这里我们简单来列举一下索引优选:

img

这个简单的例子应该可以感受到SQL优化器的作用是干什么的了,它内置很多规则,它贴合物理层,有自己的执行规则,同时又因为一些不合格的程序员写的sql不合规

SQL优化器非常重要,能到sql优化器处理的sql基本上语法都是没问题的,主要的是怎么提高sql的执行效率,这就是优化器最大的作用

只要SQL优化器处理完了以后,就会生成执行计划,这个执行计划就是存储引擎的处理单元

生成执行计划以后,他就会交给执行器,去调用存储存储引擎的相应Headler API来完成相应的执行计划

逻辑优化 → 物理优化 是整个 SQL 解析过程中最复杂、最关键的一个阶段,它不仅关系到 SQL 语句的含义是否正确,还涉及到后续的查询优化和执行效率。

逻辑优化 → 物理优化 的对比如下:

维度‌‌逻辑优化‌‌物理优化‌
‌优化目标‌语义等价性执行效率最大化
‌关注层级‌SQL语句结构存储引擎与硬件交互
‌典型操作‌子查询展开、谓词下推索引选择、缓存策略调整
‌典型输出‌逻辑执行计划物理 执行计划
‌依赖信息‌表结构、约束条件数据分布统计、索引元数据

4.1 逻辑优化 ( 生成 逻辑执行计划)

顾名思义, 逻辑分析过程就是要分析一下输入的SQL语句到底是干什么的,都有哪些操作。然后生成 逻辑查询计划,并且进行优化。

一般来讲, 一个SQL语句总有一个输入,一个输出,输入数据经过SQL加工后得到输出数据。

语句的执行顺序

标准SQL语句基本可以分解成下面7大块:


(5)SELECT 
(6)DISTINCT < select list >
(1)FROM < table source >
(2)WHERE < condition >
(3)GROUP BY < group by list >
(4)HAVING < having condition >
(7) ORDER BY < order by list >
    

计算机执行这些语句时,会按照标号 1 到 7 的顺序依次处理。

不过,有些部分是可以不写的,比如 where 子句。

如果一个sql语句的某个阶段 没写,计算机就直接跳过这一阶段。

注意:开头的 select 子句并不是最先执行的,而是处于第5个阶段,这是因为 SQL 语句这样设计,能让写代码的人更容易理解和使用,更贴合大家日常的思考习惯。

逻辑算子

在SQL处理过程中,定义了一些基本的逻辑算子(Operator),它们是执行特定操作的最小不可分割单元。以下是这些算子及其对应的基本操作:

  • TableScanOperator (TS):用于FROM操作,表示从哪个表读取数据。
  • FilterOperator (FIL):对应WHEREHAVING操作,用于根据条件筛选数据。
  • GBYOperator (GBY):涉及GROUP BYDISTINCT操作,用于对数据进行分组或去重。
  • JoinOperator (JOIN):负责JOIN操作,将两个或多个表的数据按照一定条件组合起来。
  • OrderByOperator (ORDER):执行ORDER BYLIMIT操作,用来排序结果集,并可限制返回的结果数量。
  • UnionAllOperator (UNION):实现UNIONUNION ALL操作,合并多个查询的结果。
  • SelectOperator (SEL):对应SELECT操作,选择要显示的列或计算表达式。

这些算子就像是构建块,通过它们可以构造出一个SQL查询的逻辑计划。

这个逻辑计划实际上是一个有向无环图(DAG),它展示了数据如何流动以及各个操作是如何连接在一起的。

每个算子通常都有输入和输出数据集,称之为“虚表”(vtable)。

这里的虚表不是实际存在的 数据表 ,而是逻辑上的概念,vtable 用于内部处理过程,帮助不同算子之间传递数据。

用户看不到这些 vtable 虚表,vtable 仅用于数据库系统内部管理数据流,vtable 作为算子之间的桥梁,确保数据能够按预期的方式被处理和传输。

上面的逻辑算子中,有两个 比较特殊,就是 JoinOperator (将两个或多个表的数据按照一定条件组合起来) 、 UnionAllOperator(合并多个查询的结果),这两个逻辑算子 需要处理两个或更多的输入数据集 vtable 来完成关联或合并的操作。

通过 vtable 虚表 ,整个查询就可以高效、有序地执行了。

image-20250511082551572

表达式分析

在SQL中,很多子句都可以包含表达式。

例如:


SELECT SALARY + 1 FROM T_EMPLOYEE WHERE PRODUCT_NAME = 'CAT' GROUP BY SALARY + 1

这里SELECTGROUP BYWHERE子句都包含了表达式。

解析和计算这些表达式是SQL处理过程中的重要环节。

1、类型推导

分析表达式时,要对用户输入的常量进行类型推导并标记,规则简单,如:

输入类型
100BIGINT
100.1DOUBLE
‘HELLO’STRING
TRUEBOOLEAN

2、隐式类型转换

有时,在函数调用时输入参数的类型可能不符合要求,这时就需要进行隐式类型转换。

例如,如果有一个函数fun(DOUBLE, DOUBLE),但你传入了一个整数和一个浮点数(如A—INT, B—DOUBLE),系统会尝试将整数转换成浮点数以便匹配函数签名。

比如1+2.5会被转换成double(1) + 2.5,先将整数转换为浮点数再进行加法运算。

3、布尔表达式分析

布尔表达式的分析有助于后续的SQL优化,如Join条件下推或分区裁剪等优化操作。

目的是简化复杂的布尔表达式,将其转化为最简合取范式(CNF),使表达式更易于理解和处理。

例如:

原始表达式 (T.A>10 AND P.B<100) OR T.B>10 可能被转换为 (T.A>10 OR T.B>10) AND (P.B<100 OR T.B>10)

这个过程通常包括两步:

  • 使用Quine McCluskey算法生成CNF。
  • 利用Petrick’s method算法找到最简合取范式。

4、CASE WHEN表达式分析

CASE WHEN是一个特殊的表达式,它可以像值函数一样使用,并且根据不同的条件返回不同的结果。

它有两种基本形式:

(1)、简单CASE函数:


   CASE <expr>
      WHEN <value> THEN <expr>
      ...
    ELSE <expr>
    END
    

(2)、搜索CASE函数:


   CASE
      WHEN <expr> THEN <expr>
      ...
    ELSE <expr>
    END
    

为了更好地在计算机中表示CASE WHEN表达式,把它抽象为一个三元组值函数:casewhen(condition, returnvalue1, returnvalue2)

其中condition是判断条件,returnvalue1是满足条件时的返回值,returnvalue2是不满足条件时的返回值。这样就可以结构化地表达复杂的CASE WHEN逻辑,方便后续处理和优化。

例如:


CASE WHEN A>10 THEN (CASE WHEN B>10 THEN 10 ELSE NULL) ELSE 0

可以被转换成一个表达式树,便于计算机理解和处理。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

逻辑查询计划生成

有了前面的基础,现在可以开始构建查询计划了。

根据SQL语句的执行顺序,遍历编译阶段生成的抽象语法树(AST),每当遇到特定操作时就生成相应的算子,并对表达式进行分析处理,这样就可以有序地生成整个查询计划。

举个简单的例子:

假设有如下SQL语句:


INSERT OVERWRITE TABLE Result
SELECT SUM(A + B), C
FROM T
GROUP BY C;

针对这条语句,需要构建一个查询计划,这个计划包含几个步骤:

  • 首先,计算A + B,这是为了聚合函数SUM做准备。
  • 然后,从表T中选取数据,并基于列C进行分组。
  • 最后,对每个分组应用SUM函数计算总和,并将结果插入到Result表中。

在这个过程中,有一个重要的概念叫做“初始投影”,它实际上是一个SelectOperator,用于预先计算那些在聚合函数或GROUP BY子句中使用的表达式。

比如,在上述例子中的A + B就需要通过初始投影来提前计算好,以便后续的聚合操作能够顺利进行。

早期的 SQL语法不支持在GROUP BY或聚合函数中直接使用表达式,用户如果想要实现类似的功能,只能借助子查询来完成。

随着SQL语法的扩展,现在可以直接在这些地方使用表达式,因此在解析SQL时需要判断是否需要添加初始投影步骤来确保表达式的正确计算。

此外,还有许多其他类型的SQL结构没有涵盖进来,例如JOINUNION ALL以及窗口函数等,它们各自有着不同的查询计划构建方式。

无论是 JOINUNION ALL以及窗口函数 还是 GROUP BY或聚合函数, 核心思想都是相同的:根据SQL语句的具体要求,合理安排操作顺序,确保每一步都能准确无误地执行。

image-20250511082800051

子查询 的执行计划

SQL 的语法是支持嵌套的,也就是说可以在 FROM 后面写一个完整的子查询,把它当作一张临时表来使用。

这种结构也叫做“派生表”。

举个简单的例子:


SELECT COUNT(*)
FROM (
  SELECT A.ID, B.NAME
  FROM T_EMPLOYEE A
  JOIN BEEF B
) S;

这个语句的意思是:先执行括号里的子查询,取出 T_EMPLOYEE 表和 BEEF 表连接后的结果,然后外层再统计行数。

在生成查询计划时,是这样处理的:

  • 先为子查询部分生成它自己的逻辑计划,等它执行完后,会输出一个中间结果(虚表)
  • 这个 中间结果(虚表) ,就作为外层查询的数据来源。整个过程就像是“先做小查询,再做大查询”。

这种结构虽然看起来嵌套复杂,但其实逻辑很清晰:从内到外,一层一层地执行。

这种方式让 SQL 更加灵活,也能帮助写出更清晰、更有层次感的查询语句。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

逻辑执行计划 优化

生成逻辑查询计划后,需要对其进行一些基础的优化,以去除明显不必要的计算步骤,提升整体效率。

主要包含以下三种优化:

1、常量表达式的提前计算

比如在以下 SQL 语句中:


SELECT 1+2 FROM T_EMPLOYEE

"1+2"是一个常量表达式,可以在查询执行前就将这个结果(即3)计算出来,并直接使用该结果替换原表达式,这样在实际运行时就不需要重复计算了。

2、列裁剪

当从数据库表中读取数据时,默认情况下会读取所有列的数据。

然而,在很多情况下,用户只需要用到其中几列的数据。

例如,如果用户只关心某几列用于计算,那么其他列就是多余的,读取它们只会增加不必要的时间和资源消耗。

通过列裁剪,可以去掉这些不需要的列,减少数据处理量。

3、谓词下推(Predicate Pushdown)

在进行表连接(JOIN)操作时,有时还需要在连接后应用过滤条件(WHERE)。

这时,可以通过谓词下推技术,把某些过滤条件提前到连接之前执行。

谓词下推(Predicate Pushdown) 可以减少参与连接的数据量,从而提高效率。

例如,考虑以下 SQL 语句:


SELECT * FROM A JOIN B ON A.ID = B.ID WHERE A.AGE > 10 AND B.AGE > 5

下图左边优化前,右边优化后,

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

在优化前,可能会先完成两个表的连接,然后再应用过滤条件。

优化后,则是首先根据A.AGE > 10B.AGE > 5 这些条件过滤掉不符合要求的数据,再进行连接操作。

这样一来,减少了需要连接的数据量,提高了执行效率。

通过上述优化措施,可以有效减少不必要的计算和数据传输,使查询更加高效。

比如,对于前面提到的例子,优化后的查询计划能够显著降低JOIN操作的数据量,从而加快整个查询过程的速度。

4.2 物理优化( 生成 物理执行计划)

在完成逻辑分析(验证SQL语义正确性并生成逻辑查询计划)后,MySQL进入‌物理分析‌阶段,其核心目标是将逻辑计划转化为可高效执行的‌物理查询计划‌。

物理分析 阶段是SQL优化器的核心战场,直接决定了查询的执行速度和资源消耗效率。

物理分析的核心目标

物理分析聚焦于以下三个关键维度:

1、 ‌执行效率最大化

在保证结果正确的前提下,选择最优的物理执行路径(如索引扫描 vs 全表扫描)。

2、 ‌资源消耗最小化

通过算法优化降低CPU、内存、磁盘I/O的使用量。

3、 ‌执行稳定性保障

避免极端场景下的性能波动(如内存溢出或大量随机I/O)。

物理分析的关键步骤

1、 物理算子转换

将逻辑算子映射为具体的‌物理操作符‌,其选择依赖于存储引擎特性与统计信息:

逻辑算子可能的物理实现方式
TableScan全表扫描‌(Seq Scan) / ‌索引扫描‌(Index Scan) / ‌覆盖索引扫描‌(Covering Index Scan)
Filter条件提前过滤‌(Pushdown) / ‌Bloom过滤器‌ / ‌位图扫描‌(Bitmap Scan)
Join嵌套循环连接‌(Nested Loop) / ‌哈希连接‌(Hash Join) / ‌排序合并连接‌(Merge Join)
GroupBy哈希聚合‌(Hash Aggregate) / ‌排序分组‌(Sort Group)
OrderBy内存排序‌(In-Memory Sort) / ‌外排序‌(External Merge Sort)

示例转换策略

对于逻辑算子JOIN

  • 小表驱动大表‌ → 选择‌**嵌套循环连接(Nested Loop)**‌
  • 等值连接且内存充足‌ → 选择‌哈希连接
  • 数据已预排序‌ → 选择‌排序合并连接
2、 成本估算模型

MySQL优化器通过‌成本模型‌评估不同物理路径的代价,核心参数包括:


总成本 = (数据页读取成本 × 页数) 
       + (记录处理成本 × 行数) 
       + (内存排序成本 × 排序数据集大小)
       + (网络传输成本 × 结果集大小)
       

关键统计信息‌:

  • 表级元数据‌:行数、数据页数量、平均行长度
  • 索引元数据‌:B+树高度、不同键值数量(Cardinality)、索引覆盖率
  • 系统参数‌:内存缓冲区大小、磁盘I/O速度、可用并发线程数

动态调整机制‌:

当发现WHERE product_id = 1005的选择性(Selectivity)实际为1%(而非统计信息预测的10%),优化器可能动态切换到全表扫描。

3、 高级优化策略
优化类型实现方式适用场景示例
索引跳跃扫描对复合索引(A,B,C),当A列值较少时,自动拆分为多组B,C查询WHERE B>10 AND C='X'(未指定A条件)
批处理Key访问IN (v1,v2,...vn)条件,合并多个索引查找请求为单次批量操作WHERE id IN (1001,1002,...,10000)
自适应哈希动态构建内存哈希表,将随机I/O转为顺序I/O高频重复访问热点数据
物化视图重写自动用预计算的物化视图替换原始表查询复杂聚合查询(如日报表统计)

物理查询计划示例

以电商订单查询为例:


SELECT o.order_id, u.username 
FROM orders o 
JOIN users u ON o.user_id = u.id
WHERE o.amount > 1000 
ORDER BY o.create_time DESC 
LIMIT 100;

生成的物理计划可能包括‌:

1、 ‌ 索引选择

orders表使用idx_amount索引快速过滤amount>1000

users表主键PRIMARY进行点查

2、 ‌ 连接算法

采用‌**块嵌套循环连接(BNLJ)**‌,利用Join Buffer批量处理

3、 ‌ 排序优化

使用idx_create_time索引反向扫描,避免显式排序

4、资源控制

启用优先级队列(Priority Queue)快速获取TOP 100结果

物理分析的挑战

1、 ‌统计信息滞后

当表数据频繁变更时,过时的统计信息可能导致优化器选择次优计划。

2、多目标权衡

需要平衡响应时间、资源消耗、执行稳定性等矛盾目标。

3、硬件特性适配

SSD与HDD的I/O特性差异需要不同的优化策略。

物理分析总结

物理分析是数据库系统的"执行指挥官",它通过:

  • 将逻辑计划转化为可落地的物理操作
  • 基于成本模型选择最优执行路径
  • 动态适配数据特征与硬件环境

最终输出一个由物理操作符(如IndexScan、HashJoin等)组成的 物理执行计划,交由存储引擎执行。

这个过程体现了数据库系统在理论(关系代数)与实践(硬件约束)之间的精妙平衡。

第五:执行器

这里的执行器和操作系统的操作系统差不多,都是负责调用和分发的,在sql执行中,执行器扮演两个角色

  • 执行器 调用存储引擎的 API (Headler API )处理执行计划
  • 执行器 接收存储引擎返回的结果,并将它返回给服务器端

存储引擎(InnoDB)

大家常说的索引查询,遍历查询,临时表查询等等行为都是在存储引擎中完成的

img

由于 内存的读写速度比硬盘的快,所以mysql 存储引擎(InnoDB) 有了Buffer Pool ,这里当一个查询计划来了以后,他首先会去Buffer Pool中查看是否有关这次查询的相关更新,

如果没有,就会直接去磁盘中刷出数据到Buffer Pool中,然后由存储引擎负责返回给MySQL执行器,最后返回给服务器端

当Buffer Pool中有关此次查询的更新时,需要等到存储引擎把旧的值放到undo Log(用于事务回滚的日志)中,然后就会更新Buffer Pool和把更新数据刷入到磁盘,此时就可以去根据查询条件,查询数据到Buffer Pool中。

执行器 接收存储引擎返回的结果, 然后返回给MySQL执行器

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值