绑定变量和游标 ,及绑定变量窥探

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/xxzhaobb/article/details/88641639

原文地址:https://docs.oracle.com/en/database/oracle/oracle-database/12.2/tgsql/improving-rwp-cursor-sharing.html#GUID-971F4652-3950-4662-82DE-713DDEED317C

-- 进行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

猜你喜欢

转载自blog.csdn.net/xxzhaobb/article/details/88641639