流程图
执行过程
建立连接
用户在客户端输入执行SQL,该SQL语句通过session传输到服务器端,服务器通过Server Process接收SQL语句。客户端无需再做其他的操作,只是将SQL语句发送给服务端。
查看Lib Cache
服务器进程在接到客户端传送过来的 SQL 语句后,不会直接去数据库查询。服务器进程会把这个 SQL 语句的字符进行转码,将转码后的值传递给一个 HASH 函数,并返回一个 hash 值,然后服务器进程将到 shared pool 的 library cache (高速缓存)中去查找是否存在相同的 hash 值。如果存在,服务器进程将使用这条语句已高速缓存在 library cache 中的已分析过的解析树和执行计划,省去后续的解析工作,这便是软解析。若高速缓存中不存在,则仍需要继续解析SQL、生成最佳执行计划,这便是硬解析,硬解析通常是昂贵的操作,大约占整个 SQL 执行的 70% 左右的时间。
所以,采用高速数据缓存的话,可以提高 SQL 语句的查询效率。其原因有两方面:一方面是从内存中读取数据要比从硬盘中的数据文件中读取数据效率要高,另一方面也是因为避免语句解析而节省了时间。
语法检查
分析SQL语句的语法是否符合规范,如果服务器进程认为这条 SQL 语句不符合语法规则的时候,就会把这个错误信息反馈给客户端。在这个语法检查的过程中,不会对 SQL 语句中所包含的表名、列名等等进行检查,只是检查语法。
语义检查
服务器进程接下去会对语句中涉及的表、索引、视图等对象进行解析,并对照数据字典检查这些对象的名称以及相关结构,看看这些字段、表、视图等是否在数据库中。如果存在问题的话,则数据库就会反馈错误信息给客户端。
对象解析锁
系统会对我们需要查询的对象加锁,主要是为了保障数据的一致性,防止我们在查询的过程中,其他用户对这个对象的结构发生改变。
权限核对
服务器进程还会检查连接用户是否有语句涉及对象的相关权限,若用户不具备相应权限的话则也会返回客户端。
查询转换
视图转换,将涉及视图的查询语句转换为相应的对基表查询语句。
表达式转换, 将复杂的 SQL 表达式转换为较简单的等效连接表达式。
选定执行计划
选择优化器,不同的优化器一般产生不同的“执行计划”。
选择连接方式,ORACLE有四种连接方式,对多表连接ORACLE可选择适当的连接方式。
选择连接顺序,对多表连接ORACLE选择驱动表和被驱动表。
选择数据的搜索路径,根据以上条件选择合适的数据搜索路径,如是选用全表搜索还是利用索引或是其他的方式。
在生成的多个执行计划中,按统计信息带入,找出执行成本最小的执行计划,作为执行此SQL语句的执行计划。
将SQL文本、解析树、执行计划缓存到库缓存,存放地址以及SQL语句的哈希值,以便下次执行该SQL时可直接获取相关信息。
语句执行
查询语句(Select)
首先服务器进程要判断所需数据是否在 db buffer 存在,如果存在且可用,则直接获取该数据而不是从数据库文件中去查询数据,同时根据 LRU 算法增加其访问计数;
若数据不在缓冲区中,则服务器进程将从数据库文件中查询相关数据,并把这些数据放入到数据缓冲区中( buffer cache )。
其中,判断数据的存在性和可用性检查方式为:查看 db buffer 块的头部是否有事务,如果有事务,则从回滚段中读取数据;如果没有事务,则比较 select 的 scn 和 db buffer 块头部的 scn ,如果前者小于后者,仍然要从回滚段中读取数据;如果前者大于后者,说明这是一非脏缓存,可以直接读取这个 db buffer 块的中内容。
SQL Select语句完整的执行顺序
- from子句组装来自不同数据源的数据;
- where子句基于指定的条件对记录行进行筛选;
- group by子句将数据划分为多个分组;
- 使用聚集函数进行计算;
- 使用having子句筛选分组;
- 计算所有的表达式;
- 使用order by对结果集进行排序;
- 执行select。
DML语句(Insert、Update、Delete)
-
检查所需的数据是否已经被读取到缓冲区中。如果已经存在缓冲区,则跳过第2部;
-
若所需的数据库并不在缓冲区缓存中,则服务器将数据块从数据文件读取到缓冲区中缓存;
-
对想要修改的表取得的数据行锁定( Row Exclusive Lock ),之后对所需要修改的数据行取得独占锁;
-
将数据的 Redo 记录复制到 redo log buffer ;
-
产生数据修改的 undo 数据;
-
修改 db buffer ;
-
dbwr 将修改写入数据文件;
返回客户端
SQL语句被处理完成后Select语句会将查询结果返回给客户端,DML语句执行完后数据库会将对应的执行结果返回给客户端。最终客户端按照不同的方式呈现给用户。至此该SQL语句的生命周期完毕。