SQL 语句是如何执行的,虽然SQL是声明式语言,我们可以像使用英语一样使用它,不过在RDBMS(关系型数据库管理系统)中,SQL的实现方式还是有差别的。极客教程从数据库的角度来思考一下SQL是如何被执行的。

Oracle中的SQL语句是如何执行的

我们先来看下SQL在Oracle中的执行过程:

从上面这张图中可以看出,SQL语句在Oracle中经历了以下的几个步骤。

  1. 语法检查:检查SQL拼写是否正确,如果不正确,Oracle会报语法错误。
  2. 语义检查:检查SQL中的访问对象是否存在。比如我们在写SELECT语句的时候,列名写错了,系统就会提示错误。语法检查和语义检查的作用是保证SQL语句没有错误。

  3. 权限检查:看用户是否具备访问该数据的权限。

  4. 共享池检查:共享池(Shared Pool)是一块内存池,最主要的作用是缓存SQL语句和该语句的执行计划。Oracle通过检查共享池是否存在SQL语句的执行计划,来判断进行软解析,还是硬解析。那软解析和硬解析又该怎么理解呢?

    在共享池中,Oracle首先对SQL语句进行Hash运算,然后根据Hash值在库缓存(Library Cache)中查找,如果存在SQL语句的执行计划,就直接拿来执行,直接进入“执行器”的环节,这就是软解析。

    如果没有找到SQL语句和执行计划,Oracle就需要创建解析树进行解析,生成执行计划,进入“优化器”这个步骤,这就是硬解析。

  5. 优化器:优化器中就是要进行硬解析,也就是决定怎么做,比如创建解析树,生成执行计划。

  6. 执行器:当有了解析树和执行计划之后,就知道了SQL该怎么被执行,这样就可以在执行器中执行语句了。

共享池是Oracle中的术语,包括了库缓存,数据字典缓冲区等。我们上面已经讲到了库缓存区,它主要缓存SQL语句和执行计划。而数据字典缓冲区存储的是Oracle中的对象定义,比如表、视图、索引等对象。当对SQL语句进行解析的时候,如果需要相关的数据,会从数据字典缓冲区中提取。

库缓存这一个步骤,决定了SQL语句是否需要进行硬解析。为了提升SQL的执行效率,我们应该尽量避免硬解析,因为在SQL的执行过程中,创建解析树,生成执行计划是很消耗资源的。

你可能会问,如何避免硬解析,尽量使用软解析呢?在Oracle中,绑定变量是它的一大特色。绑定变量就是在SQL语句中使用变量,通过不同的变量取值来改变SQL的执行结果。这样做的好处是能提升软解析的可能性,不足之处在于可能会导致生成的执行计划不够优化,因此是否需要绑定变量还需要视情况而定。

举个例子,我们可以使用下面的查询语句:

SQL> select * from player where player_id = 10001;
SQL

你也可以使用绑定变量,如:

SQL> select * from player where player_id = :player_id;
SQL

这两个查询语句的效率在Oracle中是完全不同的。如果你在查询player_id = 10001之后,还会查询10002、10003之类的数据,那么每一次查询都会创建一个新的查询解析。而第二种方式使用了绑定变量,那么在第一次查询之后,在共享池中就会存在这类查询的执行计划,也就是软解析。

因此我们可以通过使用绑定变量来减少硬解析,减少Oracle的解析工作量。但是这种方式也有缺点,使用动态SQL的方式,因为参数不同,会导致SQL的执行效率不同,同时SQL优化也会比较困难。

MySQL中的SQL语句是如何执行的

Oracle中采用了共享池来判断SQL语句是否存在缓存和执行计划,通过这一步骤我们可以知道应该采用硬解析还是软解析。那么在MySQL中,SQL是如何被执行的呢?

首先MySQL是典型的C/S架构,即Client/Server架构,服务器端程序使用的mysqld。整体的MySQL流程如下图所示:

你能看到MySQL由三层组成:

  1. 连接层:客户端和服务器端建立连接,客户端发送SQL至服务器端;
  2. SQL层:对SQL语句进行查询处理;
  3. 存储引擎层:与数据库文件打交道,负责数据的存储和读取。

其中SQL层与数据库文件的存储方式无关,我们来看下SQL层的结构:

  1. 询缓存:Server如果在查询缓存中发现了这条SQL语句,就会直接将结果返回给客户端;如果没有,就进入到解析器阶段。需要说明的是,因为查询缓存往往效率不高,所以在MySQL8.0之后就抛弃了这个功能。
  2. 解析器:在解析器中对SQL语句进行语法分析、语义分析。

  3. 优化器:在优化器中会确定SQL语句的执行路径,比如是根据全表检索,还是根据索引来检索等。

  4. 执行器:在执行之前需要判断该用户是否具备权限,如果具备权限就执行SQL查询并返回结果。在MySQL8.0以下的版本,如果设置了查询缓存,这时会将查询结果进行缓存。

你能看到SQL语句在MySQL中的流程是:SQL语句→缓存查询→解析器→优化器→执行器。在一部分中,MySQL和Oracle执行SQL的原理是一样的。

与Oracle不同的是,MySQL的存储引擎采用了插件的形式,每个存储引擎都面向一种特定的数据库应用环境。同时开源的MySQL还允许开发人员设置自己的存储引擎,下面是一些常见的存储引擎:

  1. InnoDB存储引擎:它是MySQL 5.5版本之后默认的存储引擎,最大的特点是支持事务、行级锁定、外键约束等。
  2. MyISAM存储引擎:在MySQL 5.5版本之前是默认的存储引擎,不支持事务,也不支持外键,最大的特点是速度快,占用资源少。

  3. Memory存储引擎:使用系统内存作为存储介质,以便得到更快的响应速度。不过如果mysqld进程崩溃,则会导致所有的数据丢失,因此我们只有当数据是临时的情况下才使用Memory存储引擎。

  4. NDB存储引擎:也叫做NDB Cluster存储引擎,主要用于MySQL Cluster分布式集群环境,类似于Oracle的RAC集群。

  5. Archive存储引擎:它有很好的压缩机制,用于文件归档,在请求写入时会进行压缩,所以也经常用来做仓库。

需要注意的是,数据库的设计在于表的设计,而在MySQL中每个表的设计都可以采用不同的存储引擎,我们可以根据实际的数据处理需要来选择存储引擎,这也是MySQL的强大之处。

总结

我们在使用SQL的时候,往往只见树木,不见森林,不会注意到它在各种数据库软件中是如何执行的,今天我们从全貌的角度来理解这个问题。你能看到不同的RDBMS之间有相同的地方,也有不同的地方。

相同的地方在于Oracle和MySQL都是通过解析器→优化器→执行器这样的流程来执行SQL的。

但Oracle和MySQL在进行SQL的查询上面有软件实现层面的差异。

  • Oracle提出了共享池的概念,通过共享池来判断是进行软解析,还是硬解析。
  • 在MySQL中,8.0以后的版本不再支持查询缓存,而是直接执行解析器→优化器→执行器的流程,这一点从MySQL中的show profile里也能看到。同时MySQL的一大特色就是提供了各种存储引擎以供选择,不同的存储引擎有各自的使用场景,我们可以针对每张表选择适合的存储引擎。

关于SQL的进一步学习,推荐极客教程提供了深入浅出的SQL教程

SQL 语句是如何执行的的更多相关文章

  1. SQLServer中SQL语句与可执行二进制语句

    SQLServer可以执行正常SQL语句也可以执行被转换的二进制语句,一般会用此方法进行数据库注入操作,骗过基本的字符过滤 --将二进制格式转为普通SQL语句 ) = 0x53454C45435420 ...

  2. SQL语句完整的执行顺序(02)

    这是对SQL语句完整的执行顺序(01)的补充: 数据库是mysql,使用的数据库表名称是my_student. 表的完整数据信息是: 完整语法是: Select [select选项] 字段列表[字段别 ...

  3. 查看SQL语句的真实执行计划

    DBMS_XPLAN包中display_cursor函数不同于display函数,display_cursor用于显示SQL语句的真实的执行计划,在大多数情况下,显示真实的执行计划有助于更好的分析SQ ...

  4. 单表:SQL语句关键字的执行顺序

    表和数据: -- 创建表 CREATE TABLE `person` ( `id` ) NOT NULL AUTO_INCREMENT, `name` ) NOT NULL, `age` ) ', ` ...

  5. MySQL的EXPLAIN命令用于SQL语句的查询执行计划

    MySQL的EXPLAIN命令用于SQL语句的查询执行计划(QEP).这条命令的输出结果能够让我们了解MySQL 优化器是如何执行SQL 语句的.这条命令并没有提供任何调整建议,但它能够提供重要的信息 ...

  6. 一条 SQL 语句是如何执行的

    一条 SQL 语句是如何执行的 SQL查询语句 select * from user where ID=10; MySQL 的基本架构可以分为 Server 层和存储引擎两部分.Server 层又包含 ...

  7. 如何使用SQLPLUS分析SQL语句(查询执行计划跟踪)

    方法一:autotrace 1,  connect sys/密码 as sysdba,在sys用户下运行$ORACLE_HOME/sqlplus/admin/plustrce.sql这段sql的实际内 ...

  8. SqlServer中Sql语句的逻辑执行顺序

    准备数据 Sql脚本如下,两张表,一张客户表Customers只包含customerid和city字段,一张订单表Orders包含orderid和customerid(关联Customers的cust ...

  9. Sql server 数据库中,纯SQL语句查询、执行 单引号问题。

    在默认值情况下, select 'abc',Titile from tb_Name;  ---输出内容 是abc: 如果想输出 单引号 'abc,需要使用select '''abc',Titile f ...

随机推荐

  1. easyUI--入门实例

    ui框架 1.需要导入的所有jar包,以及外部的类或文件 1.1导入jar包 1.2导入WebContent外部资源 1.3导入所有需要的辅助类--Util包 2.实例代码 2.1创建TreeNode ...

  2. c# 关于mongo bson转json的问题

    问题解决自:https://stackoverflow.com/questions/27132968/convert-mongodb-bsondocument-to-valid-json-in-c-s ...

  3. 搭建自己的博客(九):使用shell模式批量添加博客文章并增加分页功能

    想做个博客分页功能,但是没有太多的文章.所以使用shell命令行创建多篇文章. 1.打开pycharm下的terminal终端 python manage.py shell # 打开python终端 ...

  4. Unity使用Xcode将项目打包成IPA

    https://blog.csdn.net/Superficialtise/article/details/79699813 Unity是个开放性的平台,打包时也可以选择多种打包类型,几乎包含了所有的 ...

  5. java equals 和 == 区别

    equals 可以重写, == 不可重写 equals 是方法 equals 是 Object 的方法. 基本作用:判断两个对象是否为引用 public class Object { // 省略部分代 ...

  6. C++标准库分析总结(四)——<Vector、Array、Forward_list设计原则>

    本节主要总结标准库Vector和Array的设计方法和特性以及相关迭代器内部特征 1.Vector 1.1 Vector 内部实现 Vector是自增长的数组,其实在标准库中没有任何一种容器能原地扩充 ...

  7. Python3中转换字符串编码

    在使用subprocess调用Windows命令时,遇到了字符串不显示中文的问题,源码如下:#-*-coding:utf-8-*-__author__ = '$USER' #-*-coding:utf ...

  8. 20165223《网络对抗技术》Exp 8 Web基础

    目录 -- Web基础 实践说明 实践目标 基础问答 实践内容 Web前端:HTML Web前端:JavaScript Web后端:MySQL Web后端:PHP SQL注入,XSS攻击测试 实验遇到 ...

  9. ROC与AUC的定义与使用详解

    分类模型评估: 指标 描述 Scikit-learn函数 Precision 精准度 from sklearn.metrics import precision_score Recall 召回率 fr ...

  10. 神经网络模型(Backbone)

    自己搭建神经网络时,一般都采用已有的网络模型,在其基础上进行修改.从2012年的AlexNet出现,如今已经出现许多优秀的网络模型,如下图所示. 主要有三个发展方向: Deeper:网络层数更深,代表 ...