谈谈CURSOR(4) SQL的执行(Oracle官方的说法)
根据Oracle官方的说法,SQL语句的执行有以下步骤:
l [1] Syntactic - 语法检查
l [2] Semantic - 确认所有对象都是存在并且可以访问
l [3] View Merging - 进行查询重写优化
l [4] Statement Transformation – 将复杂的查询分解
l [5] Optimization - 确定访问方式,选择优化策略
l [6] QEP Generation - 形成执行计划
l [7] QEP Execution - 执行
步骤 [1]-[6] 就是通常所说的“分析”(PARSING),第七步就是通常所说的执行(EXECUTION)。为了不重复解析相同的SQL语句,在第一次解析之后, ORACLE将SQL语句存放在LIBRARY CACHE中.这块位于系统全局区域SGA的共享池中的内存可以被所有的数据库用户共享. 因此,当你执行一个SQL语句时,如果它和之前的执行过的语句完全相同, ORACLE就能很快获得已经被解析的语句以及最好的执行路径. ORACLE的这个功能大大地提高了SQL的执行性能并节省了内存的使用。
下面一个表格更加详细的描述了SQL的执行:
|
PARSE |
SQL匹配,语法语义检查 |
通过对LIBRARY CACHE中对象的比对,进行匹配。 |
|
Query Transformation |
对子查询,视图等进行重新组合和SQL改写 |
|
RBO - 根据规则制定执行计划 |
CBO |
判断对象访问的开销以及结果集的大小 |
每个对象都独立计算成本以及返回的结果集的大小. |
|
CBO-判断不同的连接顺序的不同开销 |
连接方式和连接顺序被通盘考虑,并且找到开销最小的连接方式 |
这个步骤里面包含了SQL执行计划的优化 |
|
产生执行树 |
执行树被生成后放在LIBRARY CACHE里,当SQL执行的时候,被用来驱动查询. |
|
|
EXECUTE |
分配绑定变量需要的内存空间,绑定变量的值实现绑定。使用上一步产生的执行计划执行SQL. |
|
FETCH |
对于SELECT操作,比普通的SQL多了一个FETCH步骤,在这个步骤中,实际上的DB BLOCK的访问才会产生。在这个阶段,将剔除不需要的数据,把结果放入结果集,传输给客户端. |
我们在10046 Trace里可以很清楚的看到这些SQL执行的步骤。不过实际上的SQL执行并不像上面所述的那么清晰明了和简单。这些步骤之间可能会产生交叉和重叠。部分操作可能提前,部分操作可能滞后。比如说对于使用绑定变量情况下的VALUE PEEKING,要实现PEEKING,分析中的优化步骤可能延后到执行阶段进行,因为只有在执行阶段,绑定变量的值才是明确的。
为了有效的共享SQL,Oracle采用下面的判断流程(以下流程来自Oracle官方的说明):
SQL语句提交
|
这个CURSOR是否打开状态? ---------------YES----V
| |
NO |
| |
SESSION_CACHED_CURSORS >0 | 这些情况,都不需要
并且CURSOR --------------YES----V 重新分析,可以直接
在Session Cursor cache里存在? | 执行
| |
NO |
| |
HOLD_CURSOR=Y |
并且cursor 在 --------------YES----V
Held cursor cache 里? |
| |
NO |
| | ^
打开一个 CURSOR | CLIENT 端 |
|--------------------------------------------| -------------|
对SQL语句生成HASHVALUE并比较 | SERVER 端 |
SQLAREA里的CURSOR是否存在这个SQL | V
| V
SQL存在? --YES-(Soft Parse)----> ---------
| | |
NO | EXECUTE |
| | |
PARSE ('Hard' Parse)-------------------------> ---------
(今天总算没有食言,还是写完了这一节,虽然觉得有点乱,大家凑合看吧。思路清晰的时候儿子要用我的电脑,只有等他睡了才能写点东西。下一节我们将继续探讨SQL执行,本节谈到的ORACLE的官方说法是如何实现的呢?我们如何来验证呢?)