-- 进行3个查询,不使用绑定变量
SYS@test>SELECT SUM(salary) FROM hr.employees WHERE employee_id < 101;
SUM(SALARY)
-----------
24000
SYS@test>SELECT SUM(salary) FROM hr.employees WHERE employee_id < 120;
SUM(SALARY)
-----------
163308
SYS@test>SELECT SUM(salary) FROM hr.employees WHERE employee_id < 165;
SUM(SALARY)
-----------
445608
-- 查看游标情况,发现3个语句拥有不同的父游标,没个父游标,都有一个子游标
SYS@test>SELECT SQL_TEXT, SQL_ID, VERSION_COUNT, HASH_VALUE
FROM V$SQLAREA
WHERE SQL_TEXT LIKE '%mployee%'
AND SQL_TEXT NOT LIKE '%SQL_TEXT%'
AND SQL_TEXT NOT LIKE 'SELECT *%' 2 3 4 5
6 ;
SQL_TEXT SQL_ID VERSION_COUNT HASH_VALUE
---------------------------------------------------------------------- ------------- ------------- ----------
SELECT SUM(salary) FROM hr.employees WHERE employee_id < 165 b1tvfcc5qnczb 1 191509483
SELECT SUM(salary) FROM hr.employees WHERE employee_id < 101 cn5250y0nqpym 1 2169198547
SELECT SUM(salary) FROM hr.employees WHERE employee_id < 120 au8nag2vnfw67 1 3074912455
SYS@test>
-- 使用绑定变量,可以发现version_count为1 ,说明数据库重用了相同的子游标,而不是创建三个单独的子游标
SYS@test>VARIABLE emp_id NUMBER
SYS@test>EXEC :emp_id := 101;
PL/SQL procedure successfully completed.
SYS@test>SELECT SUM(salary) FROM hr.employees WHERE employee_id < :emp_id;
SUM(SALARY)
-----------
24000
SYS@test>EXEC :emp_id := 120;
PL/SQL procedure successfully completed.
SYS@test>SELECT SUM(salary) FROM hr.employees WHERE employee_id < :emp_id;
SUM(SALARY)
-----------
163308
SYS@test>EXEC :emp_id := 165;
PL/SQL procedure successfully completed.
SYS@test>SELECT SUM(salary) FROM hr.employees WHERE employee_id < :emp_id;
SUM(SALARY)
-----------
445608
SYS@test>SELECT SQL_TEXT, SQL_ID, VERSION_COUNT, HASH_VALUE
FROM V$SQLAREA
WHERE SQL_TEXT LIKE '%mployee%'
AND SQL_TEXT NOT LIKE '%SQL_TEXT%'
AND SQL_TEXT NOT LIKE 'SELECT *%'
2 3 4 5 6
SYS@test>;
1 SELECT SQL_TEXT, SQL_ID, VERSION_COUNT, HASH_VALUE
2 FROM V$SQLAREA
3 WHERE SQL_TEXT LIKE '%mployee%'
4 AND SQL_TEXT NOT LIKE '%SQL_TEXT%'
5* AND SQL_TEXT NOT LIKE 'SELECT *%'
SYS@test>;
1 SELECT SQL_TEXT, SQL_ID, VERSION_COUNT, HASH_VALUE
2 FROM V$SQLAREA
3 WHERE SQL_TEXT LIKE '%mployee%'
4 AND SQL_TEXT NOT LIKE '%SQL_TEXT%'
5* AND SQL_TEXT NOT LIKE 'SELECT *%'
SYS@test>/
SQL_TEXT SQL_ID VERSION_COUNT HASH_VALUE
---------------------------------------------------------------------- ------------- ------------- ----------
SELECT SUM(salary) FROM hr.employees WHERE employee_id < 165 b1tvfcc5qnczb 1 191509483
SELECT SUM(salary) FROM hr.employees WHERE employee_id < :emp_id 4318cbskba8yh 1 615850960
SELECT SUM(salary) FROM hr.employees WHERE employee_id < 101 cn5250y0nqpym 1 2169198547
SELECT SUM(salary) FROM hr.employees WHERE employee_id < 120 au8nag2vnfw67 1 3074912455
SYS@test>
-- 绑定变量窥探
-- 先刷下share pool
SYS@test>alter system flush shared_pool;
System altered.
SYS@test>
-- 第一次查询,emplyee_id < 101
SYS@test>SELECT SUM(salary) FROM hr.employees WHERE employee_id < 101;
24000
SYS@test>SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR());
SQL_ID cn5250y0nqpym, child number 0
-------------------------------------
SELECT SUM(salary) FROM hr.employees WHERE employee_id < 101
Plan hash value: 2410354593
------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | | | 3 (100)| |
| 1 | SORT AGGREGATE | | 1 | 7 | | |
| 2 | TABLE ACCESS BY INDEX ROWID BATCHED| EMPLOYEES | 1 | 7 | 3 (0)| 00:00:01 |
|* 3 | INDEX RANGE SCAN | EMP_EMP_ID_PK | 1 | | 2 (0)| 00:00:01 |
------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
3 - access("EMPLOYEE_ID"<101)
20 rows selected.
SYS@test>
-- 第二次查询,employee_id < 120
SYS@test>SELECT SUM(salary) FROM hr.employees WHERE employee_id < 120;
163308
SYS@test>SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR());
SQL_ID au8nag2vnfw67, child number 0
-------------------------------------
SELECT SUM(salary) FROM hr.employees WHERE employee_id < 120
Plan hash value: 2410354593
------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | | | 3 (100)| |
| 1 | SORT AGGREGATE | | 1 | 7 | | |
| 2 | TABLE ACCESS BY INDEX ROWID BATCHED| EMPLOYEES | 20 | 140 | 3 (0)| 00:00:01 |
|* 3 | INDEX RANGE SCAN | EMP_EMP_ID_PK | 20 | | 2 (0)| 00:00:01 |
------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
3 - access("EMPLOYEE_ID"<120)
20 rows selected.
SYS@test>
-- 第三次查询,employee_id < 70000 ,走了全表扫描,优化器认为走全表扫描效率比走索引高
SYS@test>SELECT SUM(salary) FROM hr.employees WHERE employee_id < 70000;
691416
SYS@test>SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR());
SQL_ID 52700zva81q1x, child number 0
-------------------------------------
SELECT SUM(salary) FROM hr.employees WHERE employee_id < 70000
Plan hash value: 1756381138
--------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | | | 239 (100)| |
| 1 | SORT AGGREGATE | | 1 | 7 | | |
|* 2 | TABLE ACCESS FULL| EMPLOYEES | 69351 | 474K| 239 (1)| 00:00:01 |
--------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - filter("EMPLOYEE_ID"<70000)
19 rows selected.
SYS@test>
-- 使用绑定变量,再次进行测试,三次的emp_id 分别为 101,120,70000
SYS@test>VAR emp_id NUMBER
-- 第一次测试
SYS@test>EXEC :emp_id := 101;
PL/SQL procedure successfully completed.
SYS@test>SELECT SUM(salary) FROM hr.employees WHERE employee_id < :emp_id;
24000
SYS@test>SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR());
SQL_ID 4318cbskba8yh, child number 0
-------------------------------------
SELECT SUM(salary) FROM hr.employees WHERE employee_id < :emp_id
Plan hash value: 2410354593
------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | | | 3 (100)| |
| 1 | SORT AGGREGATE | | 1 | 7 | | |
| 2 | TABLE ACCESS BY INDEX ROWID BATCHED| EMPLOYEES | 1 | 7 | 3 (0)| 00:00:01 |
|* 3 | INDEX RANGE SCAN | EMP_EMP_ID_PK | 1 | | 2 (0)| 00:00:01 |
------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
3 - access("EMPLOYEE_ID"<:EMP_ID)
20 rows selected.
SYS@test>
-- 第二次测试
SYS@test>EXEC :emp_id := 120;
PL/SQL procedure successfully completed.
SYS@test>SELECT SUM(salary) FROM hr.employees WHERE employee_id < :emp_id;
163308
SYS@test>SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR());
SQL_ID 4318cbskba8yh, child number 0
-------------------------------------
SELECT SUM(salary) FROM hr.employees WHERE employee_id < :emp_id
Plan hash value: 2410354593
------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | | | 3 (100)| |
| 1 | SORT AGGREGATE | | 1 | 7 | | |
| 2 | TABLE ACCESS BY INDEX ROWID BATCHED| EMPLOYEES | 1 | 7 | 3 (0)| 00:00:01 |
|* 3 | INDEX RANGE SCAN | EMP_EMP_ID_PK | 1 | | 2 (0)| 00:00:01 |
------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
3 - access("EMPLOYEE_ID"<:EMP_ID)
20 rows selected.
SYS@test>
-- 第三次测试
SYS@test>EXEC :emp_id := 70000;
PL/SQL procedure successfully completed.
SYS@test>SELECT SUM(salary) FROM hr.employees WHERE employee_id < :emp_id;
691416
SYS@test>SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR());
SQL_ID 4318cbskba8yh, child number 0
-------------------------------------
SELECT SUM(salary) FROM hr.employees WHERE employee_id < :emp_id
Plan hash value: 2410354593
------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | | | 3 (100)| |
| 1 | SORT AGGREGATE | | 1 | 7 | | |
| 2 | TABLE ACCESS BY INDEX ROWID BATCHED| EMPLOYEES | 1 | 7 | 3 (0)| 00:00:01 |
|* 3 | INDEX RANGE SCAN | EMP_EMP_ID_PK | 1 | | 2 (0)| 00:00:01 |
------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
3 - access("EMPLOYEE_ID"<:EMP_ID)
20 rows selected.
SYS@test>
-- 上面的测试可以看到,优化器为三条语句选择了完全相同的执行计划。这个问题会有adaptive cursor sharing 来改变
-- cursor_sharing
-- 设置会话的cursor_sharing 为force,查看三个语句,发现执行计划是一样的
HR@test>ALTER SESSION SET CURSOR_SHARING=FORCE;
Session altered.
HR@test>SET LINESIZE 170
HR@test>SET PAGESIZE 0
HR@test>SELECT SUM(salary) FROM hr.employees WHERE employee_id < 101;
24000
HR@test>SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR());
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 | | | | 3 (100)| |
| 1 | SORT AGGREGATE | | 1 | 7 | | |
| 2 | TABLE ACCESS BY INDEX ROWID BATCHED| EMPLOYEES | 1 | 7 | 3 (0)| 00:00:01 |
|* 3 | INDEX RANGE SCAN | EMP_EMP_ID_PK | 1 | | 2 (0)| 00:00:01 |
------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
3 - access("EMPLOYEE_ID"<:SYS_B_0)
20 rows selected.
HR@test>
HR@test>SELECT SUM(salary) FROM hr.employees WHERE employee_id < 120;
163308
HR@test>SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR());
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 | | | | 3 (100)| |
| 1 | SORT AGGREGATE | | 1 | 7 | | |
| 2 | TABLE ACCESS BY INDEX ROWID BATCHED| EMPLOYEES | 1 | 7 | 3 (0)| 00:00:01 |
|* 3 | INDEX RANGE SCAN | EMP_EMP_ID_PK | 1 | | 2 (0)| 00:00:01 |
------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
3 - access("EMPLOYEE_ID"<:SYS_B_0)
20 rows selected.
HR@test>
HR@test>SELECT SUM(salary) FROM hr.employees WHERE employee_id < 165;
445608
HR@test>SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR());
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 | | | | 3 (100)| |
| 1 | SORT AGGREGATE | | 1 | 7 | | |
| 2 | TABLE ACCESS BY INDEX ROWID BATCHED| EMPLOYEES | 1 | 7 | 3 (0)| 00:00:01 |
|* 3 | INDEX RANGE SCAN | EMP_EMP_ID_PK | 1 | | 2 (0)| 00:00:01 |
------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
3 - access("EMPLOYEE_ID"<:SYS_B_0)
20 rows selected.
HR@test>
HR@test>SELECT SUM(salary) FROM hr.employees WHERE employee_id < 70000;
691416
HR@test>SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR());
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 | | | | 3 (100)| |
| 1 | SORT AGGREGATE | | 1 | 7 | | |
| 2 | TABLE ACCESS BY INDEX ROWID BATCHED| EMPLOYEES | 1 | 7 | 3 (0)| 00:00:01 |
|* 3 | INDEX RANGE SCAN | EMP_EMP_ID_PK | 1 | | 2 (0)| 00:00:01 |
------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
3 - access("EMPLOYEE_ID"<:SYS_B_0)
20 rows selected.
HR@test>
-- 查看V$SQLAREA,发现系统变量SYS_B_0 ,而且创建了一个父游标,一个子游标version_count=1
HR@test>COL SQL_TEXT FORMAT a36
HR@test>SELECT SQL_TEXT, SQL_ID, VERSION_COUNT, HASH_VALUE
FROM V$SQLAREA
WHERE SQL_TEXT LIKE '%mployee%'
AND SQL_TEXT NOT LIKE '%SQL_TEXT%'; 2 3 4
SELECT SUM(salary) FROM hr.employees cxx8n1cxr9khn 1 997509652
WHERE employee_id < :"SYS_B_0"
HR@test>
-- 设置cursor shared为force,也是有弊端的,比如当查询条件为<70000的时候,优化器还是选择了走索引,其实走全表扫描效率更好
HR@test>SELECT SUM(salary) FROM hr.employees WHERE employee_id < 70000;
691416
HR@test>SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR());
SQL_ID 52700zva81q1x, child number 0
-------------------------------------
SELECT SUM(salary) FROM hr.employees WHERE employee_id < 70000
Plan hash value: 1756381138
--------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | | | 239 (100)| |
| 1 | SORT AGGREGATE | | 1 | 7 | | |
|* 2 | TABLE ACCESS FULL| EMPLOYEES | 69351 | 474K| 239 (1)| 00:00:01 |
--------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - filter("EMPLOYEE_ID"<70000)
19 rows selected.
-- Adaptive cursor sharing 自适应游标共享,使包含有绑定变量的SQL语句,拥有多个执行计划
The adaptive cursor sharing feature enables a single statement that contains bind variables to use multiple execution plans
-- Bind-Sensitive Cursors
-- 插入数据,收集统计信息
HR@test>select count(*) from hr.employees;
100107
HR@test>DELETE FROM hr.employees WHERE employee_id > 999;
100000 rows deleted.
HR@test>commit;
Commit complete.
HR@test>EXEC DBMS_STATS.GATHER_TABLE_STATS ( ownname => 'hr', tabname => 'employees');
PL/SQL procedure successfully completed.
HR@test>
HR@test>ALTER TABLE hr.employees DISABLE NOVALIDATE CONSTRAINT emp_email_uk;
Table altered.
HR@test>
HR@test>DECLARE
v_counter NUMBER(7) := 1000;
BEGIN
FOR i IN 1..100000 LOOP
INSERT INTO hr.employees
VALUES (v_counter,null,'Doe','[email protected]',null,'07-
JUN-02','AC_ACCOUNT',null,null,null,50);
v_counter := v_counter + 1;
END LOOP;
END; 2 3 4 5 6 7 8 9 10
11 /
PL/SQL procedure successfully completed.
HR@test>commit;
Commit complete.
HR@test>EXEC DBMS_STATS.GATHER_TABLE_STATS ( ownname => 'hr', tabname => 'employees');
PL/SQL procedure successfully completed.
HR@test>
HR@test>alter system flush shared_pool;
System altered.
HR@test>
-- 查看直方图信息
COL TABLE_NAME FORMAT a15
COL COLUMN_NAME FORMAT a20
COL HISTOGRAM FORMAT a9
HR@test>SELECT TABLE_NAME, COLUMN_NAME, HISTOGRAM
FROM DBA_TAB_COLS
WHERE OWNER = 'HR'
AND TABLE_NAME = 'EMPLOYEES'
AND COLUMN_NAME = 'DEPARTMENT_ID'; 2 3 4 5
TABLE_NAME COLUMN_NAME HISTOGRAM
--------------- -------------------- ---------
EMPLOYEES DEPARTMENT_ID FREQUENCY
HR@test>
-- 较低的基数查询,走了索引
HR@test>VARIABLE dept_id NUMBER
EXEC :dept_id := 10;
SELECT COUNT(*), MAX(employee_id) FROM hr.employees WHERE department_id = :dept_id;HR@test>
PL/SQL procedure successfully completed.
HR@test>
COUNT(*) MAX(EMPLOYEE_ID)
---------- ----------------
1 200
HR@test>
HR@test>SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR);
PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------------------------------
SQL_ID 6pssvz434zspy, child number 0
-------------------------------------
SELECT COUNT(*), MAX(employee_id) FROM hr.employees WHERE department_id
= :dept_id
Plan hash value: 1642965905
----------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | | | 2 (100)| |
PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------------------------------
| 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_DEPARTMENT_IX | 1 | | 1 (0)| 00:00:01 |
----------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
3 - access("DEPARTMENT_ID"=:DEPT_ID)
21 rows selected.
HR@test>
-- 查看游标信息
HR@test>SELECT SQL_TEXT, CHILD_NUMBER AS CHILD#, EXECUTIONS AS EXEC,
BUFFER_GETS AS BUFF_GETS, IS_BIND_SENSITIVE AS BIND_SENS,
IS_BIND_AWARE AS BIND_AWARE, IS_SHAREABLE AS SHARABLE
FROM V$SQL
WHERE SQL_TEXT LIKE '%mployee%'
AND SQL_TEXT NOT LIKE '%SQL_TEXT%'; 2 3 4 5 6
SQL_TEXT CHILD# EXEC BUFF_GETS BIND_SENS BIND_AWARE SHARABLE
---------------------- ------ ----- ---------- --------- ---------- ---------
SELECT COUNT(*), MAX(e 0 2 187 Y N Y
mployee_id) FROM hr.em
ployees WHERE departme
nt_id = :dept_id
HR@test>
-- 再次以较高的基数查询 ,原表是走全表扫描是比较高效的,但是还是走了索引,因为优化器认为该执行计划可以共享。查询结果中的sharable为Y 。
HR@test>EXEC :dept_id := 50;
PL/SQL procedure successfully completed.
HR@test>
HR@test>SELECT COUNT(*), MAX(employee_id) FROM hr.employees WHERE department_id = :dept_id;
COUNT(*) MAX(EMPLOYEE_ID)
---------- ----------------
100045 100999
HR@test>
HR@test>SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR);
PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------------------------------
SQL_ID 6pssvz434zspy, child number 0
-------------------------------------
SELECT COUNT(*), MAX(employee_id) FROM hr.employees WHERE department_id
= :dept_id
Plan hash value: 1642965905
----------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | | | 2 (100)| |
PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------------------------------
| 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_DEPARTMENT_IX | 1 | | 1 (0)| 00:00:01 |
----------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
3 - access("DEPARTMENT_ID"=:DEPT_ID)
21 rows selected.
HR@test>
HR@test>SELECT SQL_TEXT, CHILD_NUMBER AS CHILD#, EXECUTIONS AS EXEC,
BUFFER_GETS AS BUFF_GETS, IS_BIND_SENSITIVE AS BIND_SENS,
IS_BIND_AWARE AS BIND_AWARE, IS_SHAREABLE AS SHARABLE
FROM V$SQL
WHERE SQL_TEXT LIKE '%mployee%'
AND SQL_TEXT NOT LIKE '%SQL_TEXT%'; 2 3 4 5 6
SQL_TEXT CHILD# EXEC BUFF_GETS BIND_SENS BIND_AWARE SHARABLE
---------------------- ------ ----- ---------- --------- ---------- ---------
SELECT COUNT(*), MAX(e 0 3 1218 Y N Y
mployee_id) FROM hr.em
ployees WHERE departme
nt_id = :dept_id
HR@test>
-- Bind-Aware Cursors
HR@test>EXEC :dept_id := 50;
PL/SQL procedure successfully completed.
HR@test>SELECT COUNT(*), MAX(employee_id) FROM hr.employees WHERE department_id = :dept_id;
COUNT(*) MAX(EMPLOYEE_ID)
---------- ----------------
100045 100999
HR@test>
HR@test>SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR);
PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------------------------------
SQL_ID 6pssvz434zspy, child number 0
-------------------------------------
SELECT COUNT(*), MAX(employee_id) FROM hr.employees WHERE department_id
= :dept_id
Plan hash value: 1642965905
----------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | | | 2 (100)| |
PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------------------------------
| 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_DEPARTMENT_IX | 1 | | 1 (0)| 00:00:01 |
----------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
3 - access("DEPARTMENT_ID"=:DEPT_ID)
21 rows selected.
HR@test>SELECT COUNT(*), MAX(employee_id) FROM hr.employees WHERE department_id = :dept_id;
COUNT(*) MAX(EMPLOYEE_ID)
---------- ----------------
100045 100999
HR@test>SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR);
PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------------------------------
SQL_ID 6pssvz434zspy, child number 1
-------------------------------------
SELECT COUNT(*), MAX(employee_id) FROM hr.employees WHERE department_id
= :dept_id
Plan hash value: 1756381138
--------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | | | 239 (100)| |
PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------------------------------
| 1 | SORT AGGREGATE | | 1 | 8 | | |
|* 2 | TABLE ACCESS FULL| EMPLOYEES | 100K| 781K| 239 (1)| 00:00:01 |
--------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - filter("DEPARTMENT_ID"=:DEPT_ID)
20 rows selected.
HR@test>
-- 查看游标信息 ,发现bind_aware一个是N一个是Y,Shareable一个是N一个是Y 。
HR@test>SELECT SQL_TEXT, CHILD_NUMBER AS CHILD#, EXECUTIONS AS EXEC,
BUFFER_GETS AS BUFF_GETS, IS_BIND_SENSITIVE AS BIND_SENS,
IS_BIND_AWARE AS BIND_AWARE, IS_SHAREABLE AS SHAREABLE
FROM V$SQL
WHERE SQL_TEXT LIKE '%mployee%'
AND SQL_TEXT NOT LIKE '%SQL_TEXT%'; 2 3 4 5 6
SQL_TEXT CHILD# EXEC BUFF_GETS BIND_SENS BIND_AWARE S
---------------------- ------ ----- ---------- --------- ---------- -
SELECT COUNT(*), MAX(e 0 4 2249 Y N N
mployee_id) FROM hr.em
ployees WHERE departme
nt_id = :dept_id
SELECT COUNT(*), MAX(e 1 1 884 Y Y Y
mployee_id) FROM hr.em
ployees WHERE departme
nt_id = :dept_id
HR@test>
-- 再次查询,设置变量为10,基数很小,这次优化器会选择走索引 。shareable是Y,优化器认为可以使用共享的执行计划。
HR@test>EXEC :dept_id := 10;
PL/SQL procedure successfully completed.
HR@test>SELECT COUNT(*), MAX(employee_id) FROM hr.employees WHERE department_id = :dept_id;
COUNT(*) MAX(EMPLOYEE_ID)
---------- ----------------
1 200
HR@test>SELECT * from TABLE(DBMS_XPLAN.DISPLAY_CURSOR);
PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------------------------------
SQL_ID 6pssvz434zspy, child number 2
-------------------------------------
SELECT COUNT(*), MAX(employee_id) FROM hr.employees WHERE department_id
= :dept_id
Plan hash value: 1642965905
----------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | | | 2 (100)| |
PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------------------------------
| 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_DEPARTMENT_IX | 1 | | 1 (0)| 00:00:01 |
----------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
3 - access("DEPARTMENT_ID"=:DEPT_ID)
21 rows selected.
HR@test>
HR@test>SELECT SQL_TEXT, CHILD_NUMBER AS CHILD#, EXECUTIONS AS EXEC,
BUFFER_GETS AS BUFF_GETS, IS_BIND_SENSITIVE AS BIND_SENS,
IS_BIND_AWARE AS BIND_AWARE, IS_SHAREABLE AS SHAREABLE
FROM V$SQL
WHERE SQL_TEXT LIKE '%mployee%'
AND SQL_TEXT NOT LIKE '%SQL_TEXT%'; 2 3 4 5 6
SQL_TEXT CHILD# EXEC BUFF_GETS BIND_SENS BIND_AWARE S
---------------------- ------ ----- ---------- --------- ---------- -
SELECT COUNT(*), MAX(e 0 4 2249 Y N N
mployee_id) FROM hr.em
ployees WHERE departme
nt_id = :dept_id
SELECT COUNT(*), MAX(e 1 1 884 Y Y Y
mployee_id) FROM hr.em
ployees WHERE departme
nt_id = :dept_id
SELECT COUNT(*), MAX(e 2 1 3 Y Y Y
SQL_TEXT CHILD# EXEC BUFF_GETS BIND_SENS BIND_AWARE S
---------------------- ------ ----- ---------- --------- ---------- -
mployee_id) FROM hr.em
ployees WHERE departme
nt_id = :dept_id
HR@test>
-- Example 20-17 Variations in SQL Text
-- 7个语句使用相同的绑定变量,但是执行的语句,不是完全相同的。结果就导致没有右边进行共享
HR@test>VARIABLE emp_id NUMBER
HR@test>EXEC :emp_id := 101;
PL/SQL procedure successfully completed.
HR@test>SELECT SUM(salary) FROM hr.employees WHERE employee_id < :emp_id;
SUM(SALARY)
-----------
24000
HR@test>SELECT SUM(salary) FROM hr.employees WHERE employee_id < :EMP_ID;
SUM(SALARY)
-----------
24000
HR@test>SELECT SUM(salary) FROM hr.employees WHERE employee_id < :Emp_Id;
SUM(SALARY)
-----------
24000
HR@test>SELECT SUM(salary) FROM hr.employees WHERE employee_id < :emp_id;
SUM(SALARY)
-----------
24000
HR@test>select sum(salary) from hr.employees where employee_id < :emp_id;
SUM(SALARY)
-----------
24000
HR@test>Select sum(salary) From hr.employees Where employee_id < :emp_id;
SUM(SALARY)
-----------
24000
HR@test>Select sum(salary) From hr.employees Where employee_id< :emp_id;
SUM(SALARY)
-----------
24000
--没有游标共享
HR@test>COL SQL_TEXT FORMAT a35
HR@test>SELECT SQL_TEXT, SQL_ID, VERSION_COUNT, HASH_VALUE
FROM V$SQLAREA
WHERE SQL_TEXT LIKE '%mployee%'
AND SQL_TEXT NOT LIKE '%SQL_TEXT%'; 2 3 4
SQL_TEXT SQL_ID VERSION_COUNT HASH_VALUE
----------------------------------- ------------- ------------- ----------
SELECT SUM(salary) FROM hr.employee bkrfu3ggu5315 1 3751971877
s WHERE employee_id < :EMP_ID
SELECT SUM(salary) FROM hr.employee 70mdtwh7xj9gv 1 265856507
s WHERE employee_id < :Emp_Id
Select sum(salary) From hr.employee 18tt4ny9u5wkt 1 2476929625
s Where employee_id< :emp_id
SELECT SUM(salary) FROM hr.employee 4318cbskba8yh 1 615850960
s WHERE employee_id < :emp_id
SQL_TEXT SQL_ID VERSION_COUNT HASH_VALUE
----------------------------------- ------------- ------------- ----------
select sum(salary) from hr.employee 633zpx3xm71kj 1 4214457937
s where employee_id < :emp_id
Select sum(salary) From hr.employee 1mqbbbnsrrw08 1 830205960
s Where employee_id < :emp_id
6 rows selected.
HR@test>
--Example 20-18 Bind Length Mismatch
-- 绑定变量不同的长度,但是名称是一样的 ,数据库并没有共享相同的cursor
HR@test>VARIABLE lname VARCHAR2(20)
HR@test>EXEC :lname := 'Taylor';
PL/SQL procedure successfully completed.
HR@test>SELECT SUM(salary) FROM hr.employees WHERE last_name = :lname;
SUM(SALARY)
-----------
11800
HR@test>VARIABLE lname VARCHAR2(100)
HR@test>EXEC :lname := 'Taylor';
PL/SQL procedure successfully completed.
HR@test>SELECT SUM(salary) FROM hr.employees WHERE last_name = :lname;
SUM(SALARY)
-----------
11800
HR@test>COL SQL_TEXT FORMAT a35
HR@test>SELECT SQL_TEXT, SQL_ID, VERSION_COUNT, HASH_VALUE
FROM V$SQLAREA
WHERE SQL_TEXT LIKE '%mployee%'
AND SQL_TEXT NOT LIKE '%SQL_TEXT%'; 2 3 4
SQL_TEXT SQL_ID VERSION_COUNT HASH_VALUE
----------------------------------- ------------- ------------- ----------
SELECT SUM(salary) FROM hr.employee buh8j4557r0h1 2 1249608193
s WHERE last_name = :lname
HR@test>
-- 没有游标进行共享,尽管执行语句是一样的。因为变量的长度不一样
HR@test>COL BIND_LENGTH_UPGRADEABLE FORMAT a15
HR@test>SELECT s.SQL_TEXT, s.CHILD_NUMBER,
c.BIND_LENGTH_UPGRADEABLE
FROM V$SQL s, V$SQL_SHARED_CURSOR c
WHERE SQL_TEXT LIKE '%employee%'
AND SQL_TEXT NOT LIKE '%SQL_TEXT%'
AND s.CHILD_ADDRESS = c.CHILD_ADDRESS;
2 3 4 5 6
SQL_TEXT CHILD_NUMBER BIND_LENGTH_UPG
----------------------------------- ------------ ---------------
SELECT SUM(salary) FROM hr.employee 0 N
s WHERE last_name = :lname
SELECT SUM(salary) FROM hr.employee 1 Y
s WHERE last_name = :lname
HR@test>
HR@test>VARIABLE emp_id NUMBER
HR@test>EXEC :emp_id := 110;
PL/SQL procedure successfully completed.
HR@test>ALTER SESSION SET OPTIMIZER_MODE = FIRST_ROWS;
Session altered.
HR@test>SELECT salary FROM hr.employees WHERE employee_id < :emp_id;
SALARY
----------
24000
17000
17000
9000
6000
4800
4800
4200
12008
9000
10 rows selected.
HR@test>ALTER SESSION SET OPTIMIZER_MODE = ALL_ROWS;
Session altered.
HR@test>SELECT salary FROM hr.employees WHERE employee_id < :emp_id;
SALARY
----------
24000
17000
17000
9000
6000
4800
4800
4200
12008
9000
10 rows selected.
-- 查询,发现,不匹配的优化器模式
HR@test>SELECT S.SQL_TEXT, S.CHILD_NUMBER, s.CHILD_ADDRESS,
C.OPTIMIZER_MODE_MISMATCH
FROM V$SQL S, V$SQL_SHARED_CURSOR C
WHERE SQL_TEXT LIKE '%employee%'
AND SQL_TEXT NOT LIKE '%SQL_TEXT%'
AND S.CHILD_ADDRESS = C.CHILD_ADDRESS; 2 3 4 5 6
SQL_TEXT CHILD_NUMBER CHILD_ADDRESS O
----------------------------------- ------------ ---------------- -
SELECT salary FROM hr.employees WHE 0 000000007CB9F948 N
RE employee_id < :emp_id
SELECT salary FROM hr.employees WHE 1 0000000075E07D80 Y
RE employee_id < :emp_id
HR@test>
END