查看真实的执行计划 绑定变量对执行计划的影响--“绑定变量窥探”

本文深入探讨了Oracle数据库中执行计划的生成与分析方法,包括如何使用DBMS_XPLAN包的不同功能来查看执行计划,理解执行计划中的操作符及统计信息,并通过实例展示了绑定变量对执行计划的影响。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

- -#####################################################
- -####     AWR执行计划                             ####
- -#####################################################
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_AWR('8qfs8857jc8fw',NULL,NULL,'ADVANCED')); 
 
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_AWR('8qfs8857jc8fw'))
 
 
SELECT TF.* FROM DBA_HIST_SQLTEXT HT, TABLE(DBMS_XPLAN.DISPLAY_AWR(HT.SQL_ID, NULL, NULL, 'all')) TF WHERE HT.SQL_TEXT LIKE '%mac%';  

- -#####################################################
- -####     dbms_xplan.display_cursor方式查看       ####
- -#####################################################
SQL > conn cqwr /cqwr

SELECT T_LTE_CARD_INFO.PK, 
       T_LTE_CARD_INFO.IMSI, 
       T_LTE_CARD_INFO.ICCID, 
       T_LTE_CARD_INFO.PIN1, 
       T_LTE_CARD_INFO.PIN2, 
       T_LTE_CARD_INFO.PUK1, 
       T_LTE_CARD_INFO.PUK2, 
       T_LTE_CARD_INFO.KI, 
       T_LTE_CARD_INFO.EKI, 
       T_LTE_CARD_INFO.STATUS 
   FROM T_LTE_CARD_INFO SAMPLE ( 5), 
       T_HLR_MSISDN 
  WHERE T_HLR_MSISDN.HLR_PK = 'HLR12' 
    AND T_LTE_CARD_INFO.SUB_IMSI = '46002' 
    AND T_LTE_CARD_INFO.MSISDN = T_HLR_MSISDN.PK 
    AND ROWNUM < = 5

select A.SQL_ID,A.HASH_VALUE,A.CHILD_NUMBER,A.SQL_TEXT from v$ sql a where A.SQL_TEXT like 'SELECT T_LTE_CARD_INFO.PK,%' 
- - 0jq118yf3w76u     2621316314     0
 
- - 传入HASH_VALUE
select * from table (dbms_xplan.display_cursor( 2621316314 , 0 , 'ADVANCED' ));

- - 传入SQL_ID
- - - 为了获取缓存库中的执行计划,可以直接查询动态性能视图v$sql_plan和v$sql_plan_statistics_all等,但更方便的方法是:
select t. * from v$ sql s, table (dbms_xplan.display_cursor(s.sql_id,s.child_number, 'allstats last' )) t where s.sql_id = '0jq118yf3w76u' ;

- - - 当前查看的方式如下
SQL > select * from table (dbms_xplan.display_cursor);
PLAN_TABLE_OUTPUT
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
SQL_ID  b4vp4vx8q5jny, child number 0
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
SELECT T_LTE_CARD_INFO.PK,        T_LTE_CARD_INFO.IMSI,        T_LTE_CARD_INFO.ICCID,
   T_LTE_CARD_INFO.PIN1,        T_LTE_CARD_INFO.PIN2,        T_LTE_CARD_INFO.PUK1,
T_LTE_CARD_INFO.PUK2,        T_LTE_CARD_INFO.KI,        T_LTE_CARD_INFO.EKI,
T_LTE_CARD_INFO.STATUS    FROM T_LTE_CARD_INFO SAMPLE ( 5 ),        T_HLR_MSISDN   WHERE
T_HLR_MSISDN.HLR_PK = 'HLR12'      AND T_LTE_CARD_INFO.SUB_IMSI = '46002'      AND
T_LTE_CARD_INFO.MSISDN = T_HLR_MSISDN.PK     AND ROWNUM < = 5

Plan hash value : 1908090178


PLAN_TABLE_OUTPUT
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
| Id  | Operation                       | Name             | Rows   | Bytes | Cost (%CPU)| Time      |
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|    0 | SELECT STATEMENT                |                 |       |       |      8 ( 100 )|          |
| *    1 |   COUNT STOPKEY                 |                 |       |       |            |          |
|    2 |    TABLE ACCESS BY INDEX ROWID  | T_LTE_CARD_INFO |      6 |   1308 |      6    ( 0 )| 00:00: 01 |
|    3 |    NESTED LOOPS                |                 |      6 |   1542 |      8    ( 0 )| 00:00: 01 |
|    4 |      TABLE ACCESS BY INDEX ROWID| T_HLR_MSISDN    |     38 |   1482 |      2    ( 0 )| 00:00: 01 |
| *    5 |       INDEX RANGE SCAN          | IND_HLR_PK      |       |       |      1    ( 0 )| 00:00: 01 |
| *    6 |      INDEX RANGE SCAN           | IND_MS_SU       |      6 |       |      5    ( 0 )| 00:00: 01 |
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

PLAN_TABLE_OUTPUT
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

Predicate Information (identified by operation id):
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

    1 - filter(ROWNUM < = 5 )
    5 - access ( "T_HLR_MSISDN" . "HLR_PK" = 'HLR12' )
    6 - access ( "T_LTE_CARD_INFO" . "MSISDN" = "T_HLR_MSISDN" . "PK" AND
               "T_LTE_CARD_INFO" . "SUB_IMSI" = '46002' )
       filter(ORA_HASH(ROWID, 0 , 2038870484 , 'SYS_SAMPLE' , 0 ) < 214748365 )
32 rows selected.

- - - - 查看执行计划中的 获取a - rows 信息 E ROWS 预估的行数 - - - - -
- - - - 需要 alter session set statistics_level = all / * + gather_plan_statistics * /

SQL > select * from table (dbms_xplan.display_cursor( null , null , 'ALLSTATS LAST' ));

SQL > select * from table (dbms_xplan.display_cursor( null , null , 'ADVANCED' ));

SQL > select * from table (dbms_xplan.display_cursor( null , null , 'ADVANCED ALLSTATS LAST PEEKED_BINDS' ));


PLAN_TABLE_OUTPUT
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
SQL_ID  b4vp4vx8q5jny, child number 1
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
SELECT T_LTE_CARD_INFO.PK,        T_LTE_CARD_INFO.IMSI,        T_LTE_CARD_INFO.ICCID,
T_LTE_CARD_INFO.PIN1,        T_LTE_CARD_INFO.PIN2,        T_LTE_CARD_INFO.PUK1,
T_LTE_CARD_INFO.PUK2,        T_LTE_CARD_INFO.KI,        T_LTE_CARD_INFO.EKI,
T_LTE_CARD_INFO.STATUS    FROM T_LTE_CARD_INFO SAMPLE ( 5 ),        T_HLR_MSISDN   WHERE
T_HLR_MSISDN.HLR_PK = 'HLR12'      AND T_LTE_CARD_INFO.SUB_IMSI = '46002'      AND
T_LTE_CARD_INFO.MSISDN = T_HLR_MSISDN.PK     AND ROWNUM < = 5

Plan hash value : 1908090178


PLAN_TABLE_OUTPUT
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
| Id  | Operation                       | Name             | Starts | E - Rows | A - Rows |   A - Time    | Buffers |
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
| *    1 |   COUNT STOPKEY                 |                 |       1 |        |       5 |00:00:00. 01 |       19 |
|    2 |    TABLE ACCESS BY INDEX ROWID  | T_LTE_CARD_INFO |       1 |       6 |       5 |00:00:00. 01 |       19 |
|    3 |    NESTED LOOPS                |                 |       1 |       6 |       8 |00:00:00. 01 |       15 |
|    4 |      TABLE ACCESS BY INDEX ROWID| T_HLR_MSISDN    |       1 |      38 |       3 |00:00:00. 01 |        3 |
| *    5 |       INDEX RANGE SCAN          | IND_HLR_PK      |       1 |        |       3 |00:00:00. 01 |        2 |
| *    6 |      INDEX RANGE SCAN           | IND_MS_SU       |       3 |       6 |       5 |00:00:00. 01 |       12 |
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
PLAN_TABLE_OUTPUT
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Predicate Information (identified by operation id):
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

    1 - filter(ROWNUM < = 5 )
    5 - access ( "T_HLR_MSISDN" . "HLR_PK" = 'HLR12' )
    6 - access ( "T_LTE_CARD_INFO" . "MSISDN" = "T_HLR_MSISDN" . "PK" AND
               "T_LTE_CARD_INFO" . "SUB_IMSI" = '46002' )
       filter(ORA_HASH(ROWID, 0 , 1153052846 , 'SYS_SAMPLE' , 0 ) < 214748365 )

31 rows selected.

- - #####################################################
- - ####     绑定变量对执行计划的影响  “绑定变量窥探”      ####
- - #####################################################
SQL CREATE TABLE t1 AS  SELECT * FROM DBA_OBJECTS ;
   
SQL > create index idx_t1 on t1 (object_id);
 
SQL> select count(*) from t1;
 
  COUNT(*)
----------
     74789
 
SQL> select count(distinct(object_id)) from  t1;
COUNT(DISTINCT(OBJECT_ID))
--------------------------
                     74789
 
- - - 收集统计信息
BEGIN
   sys.DBMS_STATS.gather_table_stats (
      ownname            => 'CQWR',
      tabname            => 'T1',
      estimate_percent   => NULL,
      method_opt         => 'for all indexed columns size auto',
      cascade            => TRUE);
END;


- - 先来看不执行绑定变量时候的执行计划
SQL > set wrap off
SQL > select count(*) from  t1 where object_id between 999 and 1000;

   COUNT ( * )
- - - - - - - - - -
          2

SQL> select * from table(dbms_xplan.display_cursor);
 
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
SQL_ID  arym7r4js4gy2, child number 0
-------------------------------------
select count(*) from  t1 where object_id between 999 and 1000
 
Plan hash value: 1970818898
 
----------------------------------------------------------------------------
| Id  | Operation         | Name   | Rows  | Bytes | Cost (%CPU)| Time     |
----------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |        |       |       |     2 (100)|          |
|   1 |  SORT AGGREGATE   |        |     1 |     5 |            |          |
 
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
|*  2 |   INDEX RANGE SCAN| IDX_T1 |     3 |    15 |     2   (0)| 00:00:01 |
----------------------------------------------------------------------------
 
Predicate Information (identified by operation id):
---------------------------------------------------
 
   2 - access("OBJECT_ID">=999 AND "OBJECT_ID"<=1000)
19 rows selected.
 
SQL> 

SQL > select count(*) from  t1 where object_id between 0 and 50000;

   COUNT ( * )
- - - - - - - - - -
      47490

SQL > select * from table(dbms_xplan.display_cursor);

PLAN_TABLE_OUTPUT
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
SQL_ID   3qwssaf8f9kgt , child number 0
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
select count ( * ) from   t1 where object_id between 0 and 50000

Plan hash value : 2101382132

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
| Id  | Operation              | Name    | Rows   | Bytes | Cost (%CPU)| Time      |
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|    0 | SELECT STATEMENT       |        |       |       |     27 ( 100 )|          |
|    1 |  SORT AGGREGATE        |        |      1 |      5 |            |          |

PLAN_TABLE_OUTPUT
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
| *    2 |    INDEX FAST FULL SCAN| IDX_T1 | 46783 |    228K |     27    ( 4 )| 00:00: 01 |
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

Predicate Information (identified by operation id):
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

    2 - filter(( "OBJECT_ID" < = 50000 AND "OBJECT_ID" > = 0 ))
19 rows selected.

和我们预期的一致  INDEX RANGE SCAN  和  INDEX FAST FULL SCAN

我们使用绑定变量的方式来执行 SQL
 
SQL > var x number
SQL > var y number
SQL > exec :x :=99
PL / SQL procedure successfully completed.

SQL > exec :y :=100
PL / SQL procedure successfully completed.

SQL > select count(*) from  t1 where object_id between :x and :y ;

   COUNT ( * )
- - - - - - - - - -
          2
SQL> 
alter session set statistics_level=all ;
SQL> select * from table(dbms_xplan.display_cursor(null,null,'ADVANCED ALLSTATS LAST PEEKED_BINDS'));
 
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
SQL_ID  7pz1dg089j86a, child number 1
-------------------------------------
select count(*) from  t1 where object_id between :x and :y
 
Plan hash value: 2351893609
 
--------------------------------------------------------------------------------
| Id  | Operation          | Name   | Starts | E-Rows |E-Bytes| Cost (%CPU)| E-T
--------------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |        |      1 |        |       |     2 (100)|
|   1 |  SORT AGGREGATE    |        |      1 |      1 |     5 |            |
 
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
|*  2 |   FILTER           |        |      1 |        |       |            |
|*  3 |    INDEX RANGE SCAN| IDX_T1 |      1 |      3 |    15 |     2   (0)| 00:
--------------------------------------------------------------------------------
 
Query Block Name / Object Alias (identified by operation id):
-------------------------------------------------------------
 
   1 - SEL$1
   3 - SEL$1 / T1@SEL$1
 
Outline Data
 
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
-------------
 
  /*+
      BEGIN_OUTLINE_DATA
      IGNORE_OPTIM_EMBEDDED_HINTS
      OPTIMIZER_FEATURES_ENABLE('11.2.0.3')
      DB_VERSION('11.2.0.3')
      ALL_ROWS
      OUTLINE_LEAF(@"SEL$1")
      INDEX(@"SEL$1" "T1"@"SEL$1" ("T1"."OBJECT_ID"))
      END_OUTLINE_DATA
 
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
  */
 
Peeked Binds (identified by position):
--------------------------------------
   1 - (NUMBER): 99
   2 - (NUMBER): 100
 
Predicate Information (identified by operation id):
---------------------------------------------------
 
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
   2 - filter(:X<=:Y)
   3 - access("OBJECT_ID">=:X AND "OBJECT_ID"<=:Y)
 
Column Projection Information (identified by operation id):
-----------------------------------------------------------
 
   1 - (#keys=0) COUNT(*)[22]
 
52 rows selected.
 
--重新绑定变量 为0 --- 50000
SQL > exec :x :=0
PL / SQL procedure successfully completed.
SQL > exec :y :=50000
PL / SQL procedure successfully completed.

SQL > select count(*) from  t1 where object_id between :x and :y ;

   COUNT ( * )
- - - - - - - - - -
      47490

SQL> select * from table(dbms_xplan.display_cursor(null,null,'ADVANCED ALLSTATS LAST PEEKED_BINDS'));
 
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
SQL_ID  7pz1dg089j86a, child number 1
-------------------------------------
select count(*) from  t1 where object_id between :x and :y
 
Plan hash value: 2351893609
 
--------------------------------------------------------------------------------
| Id  | Operation          | Name   | Starts | E-Rows |E-Bytes| Cost (%CPU)| E-T
--------------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |        |      1 |        |       |     2 (100)|
|   1 |  SORT AGGREGATE    |        |      1 |      1 |     5 |            |
 
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
|*  2 |   FILTER           |        |      1 |        |       |            |
|*  3 |    INDEX RANGE SCAN| IDX_T1 |      1 |      3 |    15 |     2   (0)| 00:
--------------------------------------------------------------------------------
 
Query Block Name / Object Alias (identified by operation id):
-------------------------------------------------------------
 
   1 - SEL$1
   3 - SEL$1 / T1@SEL$1
 
Outline Data
 
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
-------------
 
  /*+
      BEGIN_OUTLINE_DATA
      IGNORE_OPTIM_EMBEDDED_HINTS
      OPTIMIZER_FEATURES_ENABLE('11.2.0.3')
      DB_VERSION('11.2.0.3')
      ALL_ROWS
      OUTLINE_LEAF(@"SEL$1")
      INDEX(@"SEL$1" "T1"@"SEL$1" ("T1"."OBJECT_ID"))
      END_OUTLINE_DATA
 
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
  */
 
Peeked Binds (identified by position):
--------------------------------------
 
   1 - (NUMBER): 99
   2 - (NUMBER): 100
 
Predicate Information (identified by operation id):
---------------------------------------------------
 
 
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
   2 - filter(:X<=:Y)
   3 - access("OBJECT_ID">=:X AND "OBJECT_ID"<=:Y)
 
Column Projection Information (identified by operation id):
-----------------------------------------------------------
 
   1 - (#keys=0) COUNT(*)[22]
 
 
52 rows selected.
 
----可以发现 两次执行计划都是走的 INDEX RANGE SCAN  
因为  Peeked Binds的值还是 99100
也就是oracle在处理有绑定变量的时候只有在硬解析的时候才去窥探一下该SQL的绑定变量。
我们可以通过一些无关紧要的DDL语句来实现硬解析。


SQL > ALTER SYSTEM FLUSH SHARED_POOL ;

SQL > select count ( * ) from   t1 where object_id between :x and :y ;

   COUNT ( * )
- - - - - - - - - -
      47490

SQL> select * from table(dbms_xplan.display_cursor(null,null,'ADVANCED ALLSTATS LAST PEEKED_BINDS'));
 
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
SQL_ID  7pz1dg089j86a, child number 0
-------------------------------------
select count(*) from  t1 where object_id between :x and :y
 
Plan hash value: 1410530761
 
--------------------------------------------------------------------------------
| Id  | Operation              | Name   | Starts | E-Rows |E-Bytes| Cost (%CPU)|
--------------------------------------------------------------------------------
|   0 | SELECT STATEMENT       |        |      1 |        |       |    48 (100)|
|   1 |  SORT AGGREGATE        |        |      1 |      1 |     5 |            |
 
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
|*  2 |   FILTER               |        |      1 |        |       |            |
|*  3 |    INDEX FAST FULL SCAN| IDX_T1 |      1 |  48267 |   235K|    48   (3)|
--------------------------------------------------------------------------------
 
Query Block Name / Object Alias (identified by operation id):
-------------------------------------------------------------
 
   1 - SEL$1
   3 - SEL$1 / T1@SEL$1
 
Outline Data
 
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
-------------
 
  /*+
      BEGIN_OUTLINE_DATA
      IGNORE_OPTIM_EMBEDDED_HINTS
      OPTIMIZER_FEATURES_ENABLE('11.2.0.3')
      DB_VERSION('11.2.0.3')
      ALL_ROWS
      OUTLINE_LEAF(@"SEL$1")
      INDEX_FFS(@"SEL$1" "T1"@"SEL$1" ("T1"."OBJECT_ID"))
      END_OUTLINE_DATA
 
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
  */
 
Peeked Binds (identified by position):
--------------------------------------
 
   1 - (NUMBER): 0
   2 - (NUMBER): 50000
 
Predicate Information (identified by operation id):
---------------------------------------------------
 
 
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
   2 - filter(:X<=:Y)
   3 - filter(("OBJECT_ID"<=:Y AND "OBJECT_ID">=:X))
 
Column Projection Information (identified by operation id):
-----------------------------------------------------------
 
   1 - (#keys=0) COUNT(*)[22]
 
 
52 rows selected.
 
SQL> 

在更换一个值 结果又会走INDEX FAST FULL SCAN 以下就略
SQL > exec :x : = 0
PL / SQL procedure successfully completed.
SQL > exec :y : = 5

可以设置这个参数来跳过 但是这个事内部参数 还是不稳定会有 BUG: 4567767 Peeked Binds 还是会发生
alter system set "_optim_peek_user_binds" = true scope = spfile ;






转载于:https://www.cnblogs.com/cure-t-x-y/p/4252035.html

<think>好的,用户问的是Oracle数据库中某一天绑定变量的语句,在第一次传入不同的参数值时执行很慢,是怎么回事。我需要分步骤分析这个问题。 首先,绑定变量在Oracle中的作用是减少硬解析,通过共享执行计划来提高效率。但有时候第一次使用不同参数时变慢,可能涉及到执行计划的问题。这时候要考虑绑定变量窥探(Bind Peeking)的影响。当第一次执行带有绑定变量的语句时,Oracle会窥探传入的值,生成一个执行计划。如果这个值不具有代表性,比如极端值,可能会导致后续查询使用不合适的计划,特别是当数据分布不均匀时。例如,如果第一次传入的值返回的数据量很大,优化器可能选择全表扫描,而实际后续查询可能参数对应的数据量很小,更适合索引扫描,这时候第一次执行就会变慢。 接下来要考虑的是直方图统计信息。Oracle的直方图帮助优化器了解数据分布,但如果没有收集或者收集不准确,优化器可能无法正确估计选择率,导致生成低效的执行计划。当第一次传入的参数对应的数据分布与直方图信息不符时,执行计划可能不佳,导致性能问题。 另外,硬解析的发生也可能导致延迟。第一次执行绑定变量语句时,Oracle需要做硬解析,生成执行计划,这过程本身比较耗时。如果系统资源紧张,比如高并发或内存不足,硬解析时间会更长,从而影响第一次执行的速度。 还有自适应游标共享(ACS)的问题。在Oracle 11g之后引入的ACS功能,允许对不同绑定值使用不同的执行计划。但如果ACS没有正确触发,或者游标没有被标记为绑定敏感,可能会导致重复使用不合适的计划影响性能。 此外,数据倾斜和索引使用不当也是可能的原因。如果某个绑定值对应的数据量极大,而执行计划没有正确使用索引,或者索引统计信息不准确,也会导致第一次执行缓慢。 针对这些可能性,解决办法可能包括检查绑定变量窥探的设置,确保统计信息准确,特别是直方图的收集。可能需要使用SQL Profile或SQL Plan Management来固定更优的执行计划。另外,升级到更高版本的Oracle,利用自适应执行计划等新特性,或者手动使用提示(hint)来指导优化器选择正确的计划也是可行的方法。 最后,用户可能需要具体分析当时的执行计划查看统计信息是否最新,是否存在数据倾斜,以及绑定变量的值是否导致了不合适的计划选择。通过这些步骤,可以定位问题所在并采取相应的优化措施。</think>这个问题通常与Oracle的**绑定变量窥探(Bind Peeking)**和**执行计划固化**机制有关。以下是分步解释和解决方案: --- ### **1. 绑定变量窥探(Bind Peeking)** - **现象**: 当第一次执行带有绑定变量的SQL语句时,Oracle会窥探(peek)传入的绑定变量值,并根据该值生成一个执行计划。如果该值具有极端性(例如极小的值或极多的重复值),可能导致生成的执行计划不适合后续其他参数值。 - **问题场景**: 例如,表 `orders` 中 `status` 字段数据分布不均: - 值 `'COMPLETED'` 占99%的数据(适合全表扫描), - 值 `'PENDING'` 占1%的数据(适合索引扫描)。 若第一次传入 `status = 'COMPLETED'`,Oracle可能生成全表扫描计划;后续传入 `'PENDING'` 时,仍强制使用全表扫描,导致性能下降。 --- ### **2. 执行计划固化** - **原因**: 生成的执行计划会被缓存到共享池(Shared Pool)中,后续相同SQL(即使绑定变量值不同)会复用该计划。若初始计划不适用于新参数,性能问题会持续。 --- ### **3. 直方图(Histogram)缺失** - **关键影响**: 若表的列未收集直方图统计信息,优化器无法感知数据分布不均,可能错误估计选择率(Selectivity)。例如: ```sql SELECT * FROM orders WHERE status = :status; -- 未收集直方图时,优化器默认均匀分布 ``` --- ### **4. 自适应游标共享(Adaptive Cursor Sharing, ACS)** - **11g+ 特性**: Oracle 11g引入ACS,允许为不同绑定变量值生成不同执行计划。但需满足以下条件: - 游标被标记为**绑定敏感(Bind Sensitive)**, - 执行计划需根据变量值变化动态调整。 **若ACS未生效**,可能导致计划固化问题。 --- ### **解决方案** #### **方法1:收集统计信息与直方图** ```sql -- 收集表统计信息并生成直方图 BEGIN DBMS_STATS.GATHER_TABLE_STATS( ownname => 'SCHEMA_NAME', tabname => 'ORDERS', method_opt => 'FOR COLUMNS SIZE 254 STATUS' -- 为列生成直方图 ); END; ``` #### **方法2:强制优化器重新生成计划** - 使用 `REOPT` 提示(12c+): ```sql SELECT /*+ REOPT */ * FROM orders WHERE status = :status; ``` - 清空共享池中的缓存计划(谨慎使用): ```sql ALTER SYSTEM FLUSH SHARED_POOL; ``` #### **方法3:使用SQL Profile或SPM固定计划** - 通过SQL Tuning Advisor生成更优的SQL Profile: ```sql DECLARE ret VARCHAR2(100); BEGIN ret := DBMS_SQLTUNE.CREATE_TUNING_TASK( sql_text => 'SELECT * FROM orders WHERE status = :status', scope => 'COMPREHENSIVE', time_limit => 60 ); DBMS_SQLTUNE.EXECUTE_TUNING_TASK(ret); END; ``` - 使用SQL Plan Management(SPM)固定最佳计划: ```sql -- 从AWR或游标缓存加载计划 DECLARE plans PLS_INTEGER; BEGIN plans := DBMS_SPM.LOAD_PLANS_FROM_CURSOR_CACHE( sql_id => 'g4w4hj5m6k7uj' -- 替换为实际SQL_ID ); END; ``` #### **方法4:升级或使用自适应特性** - 若使用Oracle 12c+,开启**自适应执行计划**: ```sql ALTER SESSION SET optimizer_adaptive_plans = TRUE; ``` --- ### **验证步骤** 1. 检查执行计划变化: ```sql SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR(sql_id => 'g4w4hj5m6k7uj')); ``` 2. 确认直方图收集: ```sql SELECT COLUMN_NAME, HISTOGRAM FROM DBA_TAB_COL_STATISTICS WHERE TABLE_NAME = 'ORDERS' AND COLUMN_NAME = 'STATUS'; ``` --- 通过以上方法,可以定位是绑定变量窥探、统计信息缺失还是执行计划固化导致的问题,并针对性优化。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值