本文参考《Oracle性能优化求生指南》
Oracle对SQL语句处理过程如下图所示:
通过上图可知,一个SQL语句处理的过程如下:
1)创建游标。
游标是内存中的一块区域用于保存当前的SQL语句的定义信息。
2)检查缓存。
每提交一个SQL语句的执行请求,Oracle都会向共享池(shared pool)的SQL Area中检索是否存在该SQL的执行计划,
如果有就不需要重新解析SQL。
3)解析SQL语句。
解析SQL语句设计检查SQL语句的语法、对象引用,以及调用Oracle优化器来确定并生成执行计划。
解析的过程如下:
① 检查SQl语句的语法是否有效,也就是这条SQL语句是否遵循SQL语言的规则,以及所有的关键字与操作符是否都有效
并被正确使用。
② 检查SQL语句在语义上是否有效。就是SQL语句引用的所有数据库对象(即表和字段)否都是有效的
③ 检查用户是否有对所有相关对象执行给定操作的安全权限。
④ 确定SQL语句的执行计划。这一步是有Oracle优化器(optimizer)来完成的。
注意:解析SQL语句是发生在为绑定变量赋值之前,所以如果一个SQL语句有绑定变量,在关联绑定变量之前该
SQL的执行计划已经生成,后面即便绑定变量被赋予不同的值执行,它们的执行计划是相同的。
4)关联绑定变量。
执行SQL语句前,所有绑定变量(表示需要有调用程序提供响应值的占位符)的值都必须黏附到这条SQL语句上。
为什么要使用绑定变量呢?
例如,插入编号为100003的学生姓名,语句如下:
SQL> select name from t_student where gid = 100003;
NAME
--------------------------------------------------------------------------------
CHENZHEN
但是如果我们想查询编号为100004的学生姓名,就需要生成新的执行计划,因为SQL语句检索缓存时,要求SQL语句必须
完全一致才可能在共享池找到匹配执行计划。怎么才能让上面SQL语句在gid值不同情况使用相同的执行计划,即后续重复执
行该查询SQL时,能从缓存查询执行计划?答案是:变量绑定,即将gid的值绑定在一个变量中,如下代码:
SQL> variable id number;
SQL> exec :id := 100003;
PL/SQL procedure successfully completed
id
---------
100003
SQL> select name from t_student where gid = :id;
NAME
--------------------------------------------------------------------------------
CHENZHEN
id
---------
100003
或
declare
v_name t_student.name%type;
p_id number;
begin
p_id := 100003;
execute immediate ' select name from t_student where gid = :1' into v_name using p_id; --动态SQL为查询语句
dbms_output.put_line('编号为'||p_id||'的学生姓名是'||v_name);
end;
使用绑定变量的原因:
① 如果绑定变量值发生变化,重新执行这条SQL语句时,它可以在共享池中找到一条相同SQL的执行计划,不需要重
新解析这条SQL语句。
② 如果其他会话也执行同一条SQL语句,它可以在共享池中找到一条相同SQL的执行计划,不需要重新解析这条SQL
语句。
5)执行SQL语句。
如果这条SQL语句不是查询语句,它的执行过程将包含DML语句或者DDL语句的执行。如果这条SQL语句是查询语句,
执行并将为语句的数据提取做准备。
6)提取游标
游标的提取是Oracle从磁盘或高速缓存中提取数据,并将提取的数据从SQL引擎返回到PL SQL引擎。为了提高查询的
性能,可以一次提取多条数据,即批量提取,这样就可以减少从SQL引擎将结果返回到PL SQL引擎的次数。关于
批量提取请参考《Oracle的bulk collect使用》
7)关闭游标
释放分配的内存并销毁游标。