简介
参考文献:03丨学会用数据库的方式思考SQL是如何执行的
以oracle和MySQL为例,讲解了sql是怎么被执行的,并且对比了执行过程中,oracle和MySQL的异同。
个人感觉,讲解的核心是SQL执行时的缓存机制。
Oracle中的sql是如何执行的
自我口述一下
sql语句在提交后,
首先进行“语法检查”,检查sql语法是否正确,关键字等的拼写是否异常;
然后进行“语义检查”,检查sql中涉及到的访问对象是否存在,比如说from的表,或者是select的字段等。
语法检查和语义检查是为了避免sql语句本身出现错误,保证sql语句是可以运行的。
然后进行“权限检查”,检查当前用户是否有所调用表的访问权限,是否可以访问这些数据。
然后进行“共享池检查”, 这一步是检查sql语句及其执行计划是否缓存在共享池中,如果当前有缓存,就将它们取出来,这个过程被称为sql语句的软解析;如果该语句和其对应的执行计划没有缓存过,那sql语句将被送进“优化器”,创建解析树对其解析,同时生成执行计划,这个过程被称为硬解析。
在执行计划就位后,就知道了sql该怎么被执行,这时候再进行“执行器”阶段,执行sql语句,返回执行结果。
共享池(shared pool)是oracle中的术语,是一块内存池,包括了库缓存区和数据字典缓存区。库缓存区主要是用来缓存sql语句和其执行计划,数据字典缓存区存储的是Oracle中各种对象,如表、视图、索引等对象,其缓存细粒度更小,但也更实用,当对sql语句进行解析的时候,如果需要相应的对象,那直接去数据字典缓存区去找。
那库缓存过程中,Oracle是怎么进行软解析的呢?
Oracle首先对SQL语句做hash运算,然后根据得到的hash值,在库缓存(library Cache)中查找,找得到就取出来,做软解析,找不到的话那就只能硬解析。
为了提升sql的执行效率,我们应该尽量避免硬解析,因为在sql的执行过程中,创建解析树,生成执行计划是相当耗资源的。
那在Oracle中,如何主动避免使用硬解析呢?
Oracle提供了一种方法,就是绑定变量。
Oracle中使用绑定变量来避免一类执行计划的无谓消耗。
在Oracle中,以下两个sql语句是会生成两套执行计划的,即使这两套执行计划是一模一样的:
select * from player where player_id = 1001
select * from player where player_id = 1002
只要后面的常数变了,那么每一次查询都会创建一个新的查询解析。这种花销是不必要的,于是Oracle提出了绑定变量:
select * from player where player_id = :player_id
采用了绑定变量后,在第一次查询后,共享池中就会缓存此类查询的执行计划,主动避免了下次的硬解析。
简单百度了下,Oracle中应该是大量使用绑定变量来主动避免硬解析。但并不是说绑定变量就是万能的,这种类似动态sql的方式,可能过于固化,优化的话也比较难。
当然,以上是官方说法,我不是很懂,只是下意识觉得过于僵硬,不容易变通
MySQL中的sql是如何执行的
Mysql的执行过程跟Oracle有相同的地方,也有不同的地方。
sql语句送入后,
首先进行缓存查询,如果缓存中有这条sql语句,那就直接把结果返回给客户端;如果没有,则进入解析器阶段。需要特殊说明的是,这种缓存查询方式效率不高,在MySQL8.0后就被抛弃了。
至于为什么说它查询效率不高,原因很简单。每次表发生变动后,比如说加入了新数据,原先依赖这张表的缓存查询就全部失效被清空,而大部分表实际上都是在时刻变动的,这种缓存机制只对不会更新的静态表有作用,对实时更新的动态表来说,这种缓存机制的作用反而是负面的,反而增加了sql的查询时间,毕竟每次运行完后还要花时间缓存一下结果,哪怕下一秒这个结果就没用了。
解析器阶段,会做语法分析和语义分析;
然后是优化器阶段,确定执行计划;
然后是执行器阶段,执行前会先进行权限鉴定,判断该用户是否具备查询权限。如果具备,则执行sql并返回结果。如果是MySQL8.0以下的版本,如果设置了查询缓存,则会同时将查询结果进行缓存。
可以看到,MySQL和Oracle的执行流程大体上是相同的,或者说执行思路是相同的。
不同的地方主要是MySQL的引擎特性引起的。MySQL作为一种优秀的开源数据库,其数据引擎采用插件的方式,提供了多种引擎可供选择,甚至,还允许开发人员设置自己的开发引擎。一些具体的开发引擎就不介绍了,放个简单的截图吧。
需要注意的一点是,MySQL中每个表的设计都可以采用不同的数据库引擎,你完全可以根据表本身的特性,灵活选择其对应的数据库引擎,这也是MySQL的强大之处。
另一个需要提的是,如何在sql中查看每一句sql在执行时所使用的资源和时间等信息。即使用profiling。具体用法就不提了,需要用到的时候自己查吧。