当SQL语句使用文字而不是绑定变量时,请设置CURSOR_SHARING初始化参数以FORCE使数据库能够将文字替换为系统生成的绑定变量。使用这种技术,数据库有时可以减少共享SQL区域中父游标的数量。
注意:
如果一条语句使用一个ORDER BY子句,则数据库不会在该子句中执行文字替换,因为将常量列号视为文字在语义上是不正确的。ORDER BY子句中的列号影响查询计划和执行,因此数据库不能共享两个具有不同列号的游标。
当CURSOR_SHARING设置为时FORCE,数据库在解析期间执行以下步骤:
- 将语句中的所有文字复制到PGA,并用系统生成的绑定变量替换它们
例如,一个应用程序可以处理以下语句:
SELECT SUBSTR(last_name, 1, 4), SUM(salary) FROM hr.employees WHERE employee_id < 101 GROUP BY last_name优化器将替换文字,包括
SUBSTR函数中的文字,如下所示:SELECT SUBSTR(last_name, :"SYS_B_0", :"SYS_B_1"), SUM(salary) FROM hr.employees WHERE employee_id < :"SYS_B_2" GROUP BY last_name - 在共享池中搜索相同的语句(相同的SQL哈希值)
如果相同的语句没有找到,则数据库执行硬分析。否则,数据库将继续进行下一步。
- 对语句执行软解析
由于前面的步骤表明,设置CURSOR_SHARING初始化参数FORCE并没有减少解析数。而是,在某些情况下,FORCE使数据库能够执行软解析而不是硬解析。另外,FORCE也不能防止SQL注入攻击,因为Oracle数据库会在发生任何注入后绑定值。
示例20-11用系统绑定变量替换文字
本示例在会话级别设置CURSOR_SHARING为FORCE,执行三个包含文字的语句,并显示每个语句的计划:
ALTER SESSION SET CURSOR_SHARING=FORCE;
SET LINESIZE 170
SET PAGESIZE 0
SELECT SUM(salary) FROM hr.employees WHERE employee_id < 101;
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR());
SELECT SUM(salary) FROM hr.employees WHERE employee_id < 120;
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR());
SELECT SUM(salary) FROM hr.employees WHERE employee_id < 165;
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR());DISPLAY_CURSOR为提高可读性而编辑的以下输出显示,所有三个语句都使用相同的计划。优化程序选择了计划,即索引范围扫描,因为它偷看了绑定到系统绑定变量的第一个值(101),并选择了该计划作为所有值的最佳选择。 实际上,该计划并不是针对所有价值的最佳计划。当值为时165,全表扫描更有效。
SQL_ID cxx8n1cxr9khn, child number 0
-------------------------------------
SELECT SUM(salary) FROM hr.employees WHERE employee_id < :"SYS_B_0"
Plan hash value: 2410354593
-------------------------------------------------------------------------------------
| Id | Operation | Name |Rows|Bytes|Cost(%CPU)|Time|
-------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | | |2 (100)| |
| 1 | SORT AGGREGATE | |1 | 8 | | |
| 2 | TABLE ACCESS BY INDEX ROWID BATCHED| EMPLOYEES |1 | 8 |2 (0) |00:00:01|
|* 3 | INDEX RANGE SCAN | EMP_EMP_ID_PK |1 | |1 (0) |00:00:01|
-------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
3 - access("EMPLOYEE_ID"<101)
查询V$SQLAREA确认Oracle Database被具有系统绑定变量的文字替换:”SYS_B_0”,并VERSION_COUNT=1为所有三个语句创建了一个父级和一个子级游标(),这意味着所有执行都共享相同的计划。
COL SQL_TEXT FORMAT a36
SELECT SQL_TEXT, SQL_ID, VERSION_COUNT, HASH_VALUE
FROM V$SQLAREA
WHERE SQL_TEXT LIKE '%mployee%'
AND SQL_TEXT NOT LIKE '%SQL_TEXT%';
SQL_TEXT SQL_ID VERSION_COUNT HASH_VALUE
------------------------------------ ------------- ------------- ----------
SELECT SUM(salary) FROM hr.employees cxx8n1cxr9khn 1 997509652
WHERE employee_id < :"SYS_B_0"
也可以看看:
- “ 专用和共享SQL区域 ”以获取有关执行的各种检查的更多详细信息
- Oracle数据库参考,了解
CURSOR_SHARING初始化参数




