淺談Oracle綁定變量

綁定變量在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跑的更快》爲指導,如有雷同,不勝榮幸!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章