浅谈Oracle绑定变量

本文涉及的产品
传统型负载均衡 CLB,每月750个小时 15LCU
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
网络型负载均衡 NLB,每月750个小时 15LCU
简介:

绑定变量在OLTP环境下,被广泛的使用;这源于OLTP的特点和sql语句的执行过程,OLTP典型的事务短,类似的sql语句执行率高,并发大;oracle在执行sql语句前会对sql语句进行hash运算,将得到的hash值和share pool中的library cache中对比,如果未命中,则这条sql语句需要执行硬解析,如果命中,则只需要进行软解析;硬解析的执行过程是先进行语义,语法分析,然后生成执行计划,最后执行sql语句,在OLTP系统中使用绑定变量可以很好的解决这个问题!

一:oltp环境下,使用绑定变量和不使用绑定变量对比
1:创建测试数据

 
  1. [oracle@dg53 ~]$ sqlplus hr/hr  
  2. SQL*Plus: Release 10.2.0.1.0 - Production on Thu Jun 14 16:54:46 2012  
  3. Copyright (c) 1982, 2005, Oracle.  All rights reserved.  
  4.  
  5. Connected to:  
  6. Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 - Production  
  7. With the Partitioning, OLAP and Data Mining options  
  8.  
  9. SQL> create table t1 as select object_id,object_name from dba_objects;  
  10. Table created.  
  11.  
  12. SQL> create index i_t1 on t1(object_id);  
  13. Index created.  
  14.  
  15. SQL> exec dbms_stats.gather_table_stats('HR','T1',CASCADE=>TRUE);  
  16. PL/SQL procedure successfully completed. 

2:不使用绑定变量情况下,进行sql trace分析,执行1万次,需要硬解析10003次,其中包含递归解析,解析时间为19.37s,cpu消耗为17.62

 
  1. SQL> alter session set tracefile_identifier='HR01';  
  2. Session altered.  
  3.  
  4. SQL> alter session set sql_trace=TRUE;  
  5. Session altered.  
  6.  
  7. SQL> begin  
  8.   2  for i in 1..10000  
  9.   3  loop  
  10.   4  execute immediate 'select * from t1 where object_id='||i;  
  11.   5  end loop;  
  12.   6* end;  
  13.  
  14. PL/SQL procedure successfully completed.  
  15.  
  16. SQL> alter session set sql_trace=FALSE;  
  17. Session altered.  
  18.  
  19. OVERALL TOTALS FOR ALL RECURSIVE STATEMENTS  
  20.  
  21. call     count       cpu    elapsed       disk      query    current        rows  
  22. ------- ------  -------- ---------- ---------- ---------- ----------  ----------  
  23. Parse    10003     17.62      19.37          0          0          0           0  
  24. Execute  10003      0.48       0.54          0          0          0           0  
  25. Fetch        7      0.00       0.01          1         13          0           4  
  26. ------- ------  -------- ---------- ---------- ---------- ----------  ----------  
  27. total    20013     18.10      19.92          1         13          0           4  
  28.  
  29. Misses in library cache during parse: 10000  
  30.  
  31. 10003  user  SQL statements in session.  
  32.     3  internal SQL statements in session.  
  33. 10006  SQL statements in session.  
  34.     0  statements EXPLAINed in this session.  
  35. ********************************************************************************  
  36. Trace file: dg53_ora_24818_HR01.trc  
  37. Trace file compatibility: 10.01.00  
  38. Sort options: default  
  39.  
  40.        0  session in tracefile.  
  41.    10003  user  SQL statements in trace file.  
  42.        3  internal SQL statements in trace file.  
  43.    10006  SQL statements in trace file.  
  44.    10006  unique SQL statements in trace file.  
  45.    80071  lines in trace file.  
  46.       78  elapsed seconds in trace file. 

3:使用绑定变量情况下,进行sql trace分析,执行1万次,只需要硬解析5次,其中包含递归解析,解析时间和cpu时间基本忽略不计

 
  1. SQL> alter session set tracefile_identifier='HR02';  
  2. Session altered.  
  3.  
  4. SQL> alter session set sql_trace=TRUE;  
  5. Session altered.  
  6.  
  7. SQL> begin  
  8.   2  for i in 1..10000  
  9.   3  loop  
  10.   4  execute immediate 'select * from t1 where object_id=:i' using i;  
  11.   5  end loop;  
  12.   6  end;  
  13. PL/SQL procedure successfully completed.  
  14.  
  15. SQL> alter session set sql_trace=FALSE;  
  16. Session altered.  
  17.  
  18. OVERALL TOTALS FOR ALL RECURSIVE STATEMENTS  
  19.  
  20. call     count       cpu    elapsed       disk      query    current        rows  
  21. ------- ------  -------- ---------- ---------- ---------- ----------  ----------  
  22. Parse        5      0.00       0.00          0          0          0           0  
  23. Execute  10004      0.10       0.09          0          0          0           0  
  24. Fetch       10      0.00       0.01          0         29          0           7  
  25. ------- ------  -------- ---------- ---------- ---------- ----------  ----------  
  26. total    10019      0.10       0.10          0         29          0           7  
  27.  
  28. Misses in library cache during parse: 2  
  29. Misses in library cache during execute: 1  
  30.  
  31.     4  user  SQL statements in session.  
  32.     4  internal SQL statements in session.  
  33.     8  SQL statements in session.  
  34.     0  statements EXPLAINed in this session.  
  35. ********************************************************************************  
  36. Trace file: dg53_ora_24818_HR02.trc  
  37. Trace file compatibility: 10.01.00  
  38. Sort options: default  
  39.  
  40.        0  session in tracefile.  
  41.        4  user  SQL statements in trace file.  
  42.        4  internal SQL statements in trace file.  
  43.        8  SQL statements in trace file.  
  44.        8  unique SQL statements in trace file.  
  45.    10078  lines in trace file.  
  46.       91  elapsed seconds in trace file. 

二:使用绑定变量有如此好的效果,那么这是不是百利无一害的技术手段呢?下面在OLAP环境下测试
1:创建测试数据,olap环境下分区的技术非常普遍,且数据量非常大

 
  1. [root@dg53 ~]# su - oracle  
  2. [oracle@dg53 ~]$ sqlplus /nolog  
  3. SQL*Plus: Release 10.2.0.1.0 - Production on Fri Jun 15 09:05:35 2012  
  4. Copyright (c) 1982, 2005, Oracle.  All rights reserved.  
  5.  
  6. SQL> conn /as sysdba  
  7. Connected.  
  8. SQL> create tablespace data01;  
  9. Tablespace created.  
  10.  
  11. SQL> create tablespace data02;  
  12. Tablespace created.  
  13.  
  14. SQL> create tablespace data03;  
  15. Tablespace created.  
  16.  
  17. SQL> create tablespace data04;  
  18. Tablespace created.  
  19.  
  20. SQL> conn hr/hr  
  21. Connected.  
  22.  
  23. SQL> create table t2 (object_id number,object_name varchar2(200))  
  24.   2  partition by range(object_id)  
  25.   3  (partition p1 values less than(5000) tablespace data01,  
  26.   4   partition p2 values less than(10000) tablespace data02,  
  27.   5   partition p3 values less than(15000) tablespace data03,  
  28.   6*  partition pm values less than(maxvalue) tablespace data04)  
  29. Table created.  
  30.  
  31. SQL> begin  
  32.   2  for i in 1..300  
  33.   3  loop  
  34.   4  insert into t2 select object_id,object_name from dba_objects;  
  35.   5  end loop;  
  36.   6  end;  
  37. PL/SQL procedure successfully completed.  
  38.  
  39. SQL> commit;  
  40. Commit complete.  
  41.  
  42. SQL> create index i_t_id on t2(object_id) local  
  43.   2  (partition p1 tablespace data01,  
  44.   3   partition p2 tablespace data02,  
  45.   4   partition p3 tablespace data03,  
  46.   5   partition pm tablespace data04);  
  47. Index created.  
  48.  
  49. SQL> exec dbms_stats.gather_table_stats('HR','T2',CASCADE=>TRUE);  
  50. PL/SQL procedure successfully completed.  
  51.  
  52. SQL> select count(*) from t2 partition(p1);  
  53.  
  54.   COUNT(*)  
  55. ----------  
  56.    1474800  
  57.  
  58. SQL> select count(*) from t2 partition(p2);  
  59.  
  60.   COUNT(*)  
  61. ----------  
  62.    1398900  
  63.  
  64. SQL> select count(*) from t2 partition(p3);  
  65.  
  66.   COUNT(*)  
  67. ----------  
  68.    1491900  
  69.  
  70. SQL> select count(*) from t2 partition(pm);  
  71.  
  72.   COUNT(*)  
  73. ----------  
  74.   10752600 

2:查询object_id落在1-5999之间的数据,查看执行计划,这里选择了全表扫描为最优的执行计划

 
  1. SQL> set autot traceonly  
  2. SQL> select  object_id,count(*) from t2 where object_id between  1  and 5999 group by object_id;  
  3. 5807 rows selected.  
  4.  
  5. Execution Plan  
  6. ----------------------------------------------------------  
  7. Plan hash value: 1765100474  
  8.  
  9. -------------------------------------------------------------------------------------------------  
  10.  
  11. | Id  | Operation                | Name | Rows  | Bytes | Cost (%CPU)| Time| Pstart| Pstop |  
  12.  
  13. -------------------------------------------------------------------------------------------------  
  14.  
  15. |   0 | SELECT STATEMENT         |      |  5484 | 27420 |  2650  (12)| 00:00:32|       |       |  
  16.  
  17. |   1 |  PARTITION RANGE ITERATOR|      |  5484 | 27420 |  2650  (12)| 00:00:32|     1 |     2 |  
  18.  
  19. |   2 |   HASH GROUP BY          |      |  5484 | 27420 |  2650  (12)| 00:00:32|       |       |  
  20.  
  21. |*  3 |    TABLE ACCESS FULL     | T2   |  1639K|  8005K|  2432   (4)| 00:00:30|     1 |     2 |  
  22.  
  23. -------------------------------------------------------------------------------------------------  
  24. Predicate Information (identified by operation id):  
  25. ---------------------------------------------------  
  26.    3 - filter("OBJECT_ID"<=5999 AND "OBJECT_ID">=1)  
  27.  
  28. Statistics  
  29. ----------------------------------------------------------  
  30.           1  recursive calls  
  31.           0  db block gets  
  32.       10772  consistent gets  
  33.       10643  physical reads  
  34.           0  redo size  
  35.      101752  bytes sent via SQL*Net to client  
  36.        4642  bytes received via SQL*Net from client  
  37.         389  SQL*Net roundtrips to/from client  
  38.           0  sorts (memory)  
  39.           0  sorts (disk)  
  40.        5807  rows processed 

3:查询object_id落在1000-15000之间的数据,查看执行计划,这里选择了索引访问扫描为最优的执行计划

 

 
  1. SQL> select object_id,count(*) from t2 where object_id between 1000 and 15000 group by object_id;  
  2. 13600 rows selected.  
  3.  
  4. Execution Plan  
  5. ----------------------------------------------------------  
  6. Plan hash value: 3236792548  
  7.  
  8. ------------------------------------------------------------------------------------------------  
  9.  
  10. | Id  | Operation             | Name   | Rows  | Bytes | Cost (%CPU)| Time     |Pstart| Pstop |  
  11.  
  12. ------------------------------------------------------------------------------------------------  
  13.  
  14. |   0 | SELECT STATEMENT      |        | 12869 | 64345 |  8731   (2)| 00:01:45 ||       |  
  15.  
  16. |   1 |  PARTITION RANGE ALL  |        | 12869 | 64345 |  8731   (2)| 00:01:45 |1 |     4 |  
  17.  
  18. |   2 |   SORT GROUP BY NOSORT|        | 12869 | 64345 |  8731   (2)| 00:01:45 ||       |  
  19.  
  20. |*  3 |    INDEX RANGE SCAN   | I_T_ID |  3847K|    18M|  8731   (2)| 00:01:45 |1 |     4 |  
  21.  
  22. ------------------------------------------------------------------------------------------------  
  23. Predicate Information (identified by operation id):  
  24. ---------------------------------------------------  
  25.    3 - access("OBJECT_ID">=1000 AND "OBJECT_ID"<=15000)  
  26.        filter("OBJECT_ID"<=15000 AND "OBJECT_ID">=1000)  
  27.  
  28. Statistics  
  29. ----------------------------------------------------------  
  30.           1  recursive calls  
  31.           0  db block gets  
  32.        9655  consistent gets  
  33.        8115  physical reads  
  34.           0  redo size  
  35.      242794  bytes sent via SQL*Net to client  
  36.       10351  bytes received via SQL*Net from client  
  37.         908  SQL*Net roundtrips to/from client  
  38.           0  sorts (memory)  
  39.           0  sorts (disk)  
  40.       13600  rows processed 


结论:由此可见,使用绑定变量应该尽量保证使用绑定变量的sql语句执行计划应当相同,否则将造成问题,因而绑定变量不适用于OLAP环境中!

三:在前面的测试中,1-5999之间的查询,为什么不选择分区范围扫描?1000-5000之间的查询,为什么不选择全表扫描,使用索引,不会产生无谓的2次I/O吗?要了解这些,就要开启数据库的10053时间,分析cbo如何选择执行计划?

1:分析1-5999之间查询的10053事件

 
  1. SQL> alter session set tracefile_identifier='HR03';  
  2. Session altered.  
  3.  
  4. SQL> alter session set events '10053 trace name context forever,level 1';  
  5. Session altered.  
  6.  
  7. SQL> select  object_id,count(*) from t2 where object_id between  1  and 5999 group by object_id;  
  8.  
  9. 5807 rows selected.  
  10.  
  11. SQL> alter session set events '10053 trace name context off';  
  12. Session altered. 

trace文件关键内容:

***************************************
Column Usage Monitoring is ON: tracking level = 1
***************************************
****************
QUERY BLOCK TEXT
****************
select  object_id,count(*) from t2 where object_id between  1  and 5999 group by object_id
*********************
QUERY BLOCK SIGNATURE
*********************
qb name was generated
signature (optimizer): qb_name=SEL$1 nbfros=1 flg=0
  fro(0): flg=0 objn=54910 hint_alias="T2"@"SEL$1"
*****************************
SYSTEM STATISTICS INFORMATION
*****************************
  Using NOWORKLOAD Stats
  CPUSPEED: 587 millions instruction/sec
  IOTFRSPEED: 4096 bytes per millisecond (default is 4096)
  IOSEEKTIM: 10 milliseconds (default is 10)
***************************************
BASE STATISTICAL INFORMATION
***********************
Table Stats::
  Table: T2  Alias: T2  (Using composite stats)
  (making adjustments for partition skews)
  ORIGINAL VALUES::    #Rows: 15078669  #Blks:  71051  AvgRowLen:  28.00
  PARTITIONS::
  PRUNED: 2
  ANALYZED: 2  UNANALYZED: 0
    #Rows: 15078669  #Blks:  10756  AvgRowLen:  28.00
Index Stats::
  Index: I_T_ID  Col#: 1
    USING COMPOSITE STATS
    LVLS: 2  #LB: 33742  #DK: 50440  LB/K: 1.00  DB/K: 303.00  CLUF: 15299802.00
  Column (#1): OBJECT_ID(NUMBER)
    AvgLen: 5.00 NDV: 50440 Nulls: 0 Density: 1.9826e-05 Min: 33 Max: 54914
***************************************
SINGLE TABLE ACCESS PATH
  Table: T2  Alias: T2
    Card: Original: 15078669  Rounded: 1639470  Computed: 1639469.86  Non Adjusted: 1639469.86
  Access Path: TableScan
    Cost:  2432.43  Resp: 2432.43  Degree: 0
      Cost_io: 2355.00  Cost_cpu: 545542277
      Resp_io: 2355.00  Resp_cpu: 545542277
  Access Path: index (index (FFS))
    Index: I_T_ID
    resc_io: 7383.00  resc_cpu: 2924443977
    ix_sel: 0.0000e+00  ix_sel_with_filters: 1
  Access Path: index (FFS)
    Cost:  7798.09  Resp: 7798.09  Degree: 1
      Cost_io: 7383.00  Cost_cpu: 2924443977
      Resp_io: 7383.00  Resp_cpu: 2924443977
  Access Path: index (IndexOnly)
    Index: I_T_ID
    resc_io: 3671.00  resc_cpu: 358846806
    ix_sel: 0.10873  ix_sel_with_filters: 0.10873
    Cost: 3721.93  Resp: 3721.93  Degree: 1
 
 Best:: AccessPath: TableScan
         Cost: 2432.43  Degree: 1  Resp: 2432.43  Card: 1639469.86  Bytes: 0
Grouping column cardinality [ OBJECT_ID]    5484 

2:分析1000-5000之间查询的10053事件

 
  1. SQL> alter session set tracefile_identifier='HR04';  
  2. Session altered.  
  3.  
  4. SQL> alter session set events '10053 trace name context forever,level 1';  
  5. Session altered.  
  6.  
  7. SQL> select object_id,count(*) from t2 where object_id between 1000 and 15000 group by object_id;  
  8. 13600 rows selected.  
  9.  
  10. SQL> alter session set events '10053 trace name context off';  
  11. Session altered. 

trace文件关键内容:

 ***************************************
Column Usage Monitoring is ON: tracking level = 1
***************************************
****************
QUERY BLOCK TEXT
****************
select object_id,count(*) from t2 where object_id between 1000 and 15000 group by object_id
*********************
QUERY BLOCK SIGNATURE
*********************
qb name was generated
signature (optimizer): qb_name=SEL$1 nbfros=1 flg=0
  fro(0): flg=0 objn=54910 hint_alias="T2"@"SEL$1"
*****************************
SYSTEM STATISTICS INFORMATION
*****************************
  Using NOWORKLOAD Stats
  CPUSPEED: 587 millions instruction/sec
  IOTFRSPEED: 4096 bytes per millisecond (default is 4096)
  IOSEEKTIM: 10 milliseconds (default is 10)
***************************************
BASE STATISTICAL INFORMATION
***********************
Table Stats::
  Table: T2  Alias: T2  (Using composite stats)
    #Rows: 15078669  #Blks:  71051  AvgRowLen:  28.00
Index Stats::
  Index: I_T_ID  Col#: 1
    USING COMPOSITE STATS
    LVLS: 2  #LB: 33742  #DK: 50440  LB/K: 1.00  DB/K: 303.00  CLUF: 15299802.00
  Column (#1): OBJECT_ID(NUMBER)
    AvgLen: 5.00 NDV: 50440 Nulls: 0 Density: 1.9826e-05 Min: 33 Max: 54914
***************************************
SINGLE TABLE ACCESS PATH
  Table: T2  Alias: T2
    Card: Original: 15078669  Rounded: 3847127  Computed: 3847127.03  Non Adjusted: 3847127.03
  Access Path: TableScan
    Cost:  16073.05  Resp: 16073.05  Degree: 0
      Cost_io: 15544.00  Cost_cpu: 3727344901
      Resp_io: 15544.00  Resp_cpu: 3727344901
  Access Path: index (index (FFS))
    Index: I_T_ID
    resc_io: 7383.00  resc_cpu: 3049910030
    ix_sel: 0.0000e+00  ix_sel_with_filters: 1
  Access Path: index (FFS)
    Cost:  7815.89  Resp: 7815.89  Degree: 1
      Cost_io: 7383.00  Cost_cpu: 3049910030
      Resp_io: 7383.00  Resp_cpu: 3049910030
  Access Path: index (IndexOnly)
    Index: I_T_ID
    resc_io: 8611.00  resc_cpu: 842035120
    ix_sel: 0.25514  ix_sel_with_filters: 0.25514
    Cost: 8730.52  Resp: 8730.52  Degree: 1
  
Best:: AccessPath: IndexFFS  Index: I_T_ID
         Cost: 7815.89  Degree: 1  Resp: 7815.89  Card: 3847127.03  Bytes: 0
Grouping column cardinality [ OBJECT_ID]    12869
***************************************

本文以《让oracle跑的更快》为指导,如有雷同,不胜荣幸!

本文转自斩月博客51CTO博客,原文链接http://blog.51cto.com/ylw6006/899353如需转载请自行联系原作者


ylw6006

相关实践学习
AnalyticDB MySQL海量数据秒级分析体验
快速上手AnalyticDB MySQL,玩转SQL开发等功能!本教程介绍如何在AnalyticDB MySQL中,一键加载内置数据集,并基于自动生成的查询脚本,运行复杂查询语句,秒级生成查询结果。
阿里云云原生数据仓库AnalyticDB MySQL版 使用教程
云原生数据仓库AnalyticDB MySQL版是一种支持高并发低延时查询的新一代云原生数据仓库,高度兼容MySQL协议以及SQL:92、SQL:99、SQL:2003标准,可以对海量数据进行即时的多维分析透视和业务探索,快速构建企业云上数据仓库。 了解产品 https://www.aliyun.com/product/ApsaraDB/ads
相关文章
|
6月前
|
Oracle 关系型数据库 数据库
Flink Sink to Oracle 存在字段CLOB类型,如何处理错误”ORA-01461: 仅能绑定要插入LONG的LONG值“
做Flink CDC同步数据过程中,目标是Oracle数据库,其中某个字段较大被设置为CLOB类型,其中会遇到异常,”ORA-01461: 仅能绑定要插入LONG的LONG值“
|
SQL 缓存 监控
为什么Oracle中包含绑定变量的SQL会有多个游标?(译文)
为了改进包含绑定变量的SQL的执行计划,Oracle在11g版本中引入了一项名为自适应游标共享(ACS,Adaptive Cursor Sharing)的新功能。
160 0
|
SQL Oracle 关系型数据库
Oracle优化09-绑定变量
Oracle优化09-绑定变量
234 0
|
SQL 缓存 Oracle
Oracle-绑定变量binding variable解读
Oracle-绑定变量binding variable解读
333 0
|
SQL 监控 Oracle
Oracle数据库---怎样获得sql语句执行时的绑定变量
绑定变量是oracle常用的优化技术,有时候我们需要获得sql运行时绑定变量的值,用10046事件跟踪会话即可获得
551 0
|
SQL Oracle 关系型数据库
|
SQL Oracle 关系型数据库
PLSQL_性能优化系列19_Oracle Explain Plan解析计划通过Profile绑定
20150529 Created By BaoXinjian   一、摘要   1. 应用场景 当运行很久的Job突然出现性能问题时,并排除数据量突然变大,可能原因有执行的脚本的某些对应的SQL的解析计划变更,在Oracle 10g中可以通过绑定profile,在11g中可以通过baseline进行绑定 2.
811 0