测试目的,当有hint时,并且hint跟需要绑定的执行计划有冲突,谁的优先级高。
.
固定执行计划-使用SQL Tuning Advisor
固定执行计划-手工指定PLAN OUTLINE
固定执行计划-手工指定索引名称的方式
固定执行计划-使用coe_xfr_sql_profile固定执行计划
固定执行计划-使用SPM(Sql Plan Management)固定执行计划
.
这里是第一个测试,使用SQL Tuning Advisor来测试:
创建测试用例:
LUNAR@lunardb>create table lunartest1 (n number ); Table created. Elapsed: 00:00:00.08 LUNAR@lunardb>begin 2 for i in 1 .. 10000 loop 3 insert into lunartest1 values(i); 4 commit; 5 end loop; 6 end; 7 / PL/SQL procedure successfully completed. Elapsed: 00:00:02.05 LUNAR@lunardb>create index idx_lunartest1_n on lunartest1(n); Index created. Elapsed: 00:00:00.04
执行查询,我们看到sql按照hint的方式没有使用索引,而是全表扫描,这是我们预期的结果:
LUNAR@lunardb>set autotrace on
LUNAR@lunardb>select /*+ no_index(lunartest1 idx_lunartest1_n) */ * from lunartest1 where n=1;
               N
----------------
               1
Elapsed: 00:00:00.00
Execution Plan
----------------------------------------------------------
Plan hash value: 1172089107
--------------------------------------------------------------------------------
| Id  | Operation         | Name       | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |            |     1 |    13 |     7   (0)| 00:00:01 |
|*  1 |  TABLE ACCESS FULL| LUNARTEST1 |     1 |    13 |     7   (0)| 00:00:01 |
--------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
   1 - filter("N"=1)
Note
-----
   - dynamic sampling used for this statement (level=2)
Statistics
----------------------------------------------------------
          5  recursive calls
          0  db block gets
         49  consistent gets
          0  physical reads
          0  redo size
        519  bytes sent via SQL*Net to client
        524  bytes received via SQL*Net from client
          2  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
          1  rows processed
LUNAR@lunardb>
下面我们运行SQL Tuning Advisor来生成建议报告:
LUNAR@lunardb>DECLARE 2 my_task_name VARCHAR2(50); 3 BEGIN 4 my_task_name := DBMS_SQLTUNE.CREATE_TUNING_TASK( 5 SQL_ID => 'bjgduva68mbqm', 6 scope => 'COMPREHENSIVE', 7 time_limit => 60, 8 task_name => 'Lunar_tunning_bjgduva68mbqm', 9 description => 'Task to tune a query on bjgduva68mbqm by Lunar'); 10 dbms_sqltune.execute_tuning_task(my_task_name); 11 dbms_output.put_line(my_task_name); 12 END; 13 / Lunar_tunning_bjgduva68mbqm PL/SQL procedure successfully completed. Elapsed: 00:00:00.20 LUNAR@lunardb>
查看生成的报告内容:
LUNAR@lunardb>SELECT dbms_sqltune.report_tuning_task('&task_name') FROM dual;  
Enter value for task_name: Lunar_tunning_bjgduva68mbqm
old   1: SELECT dbms_sqltune.report_tuning_task('&task_name') FROM dual
new   1: SELECT dbms_sqltune.report_tuning_task('Lunar_tunning_bjgduva68mbqm') FROM dual
DBMS_SQLTUNE.REPORT_TUNING_TASK('LUNAR_TUNNING_BJGDUVA68MBQM')
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
GENERAL INFORMATION SECTION
-------------------------------------------------------------------------------
Tuning Task Name   : Lunar_tunning_bjgduva68mbqm
Tuning Task Owner  : LUNAR
Workload Type      : Single SQL Statement
Scope              : COMPREHENSIVE
Time Limit(seconds): 60
Completion Status  : COMPLETED
Started at         : 01/12/2016 10:09:54
Completed at       : 01/12/2016 10:09:54
-------------------------------------------------------------------------------
Schema Name: LUNAR
SQL ID     : bjgduva68mbqm
SQL Text   : select /*+ no_index(lunartest1 idx_lunartest1_n) */ * from
             lunartest1 where n=1
-------------------------------------------------------------------------------
FINDINGS SECTION (2 findings)
-------------------------------------------------------------------------------
1- Statistics Finding
---------------------
  Table "LUNAR"."LUNARTEST1" was not analyzed.
  Recommendation
  --------------
  - Consider collecting optimizer statistics for this table.
    execute dbms_stats.gather_table_stats(ownname => 'LUNAR', tabname =>
            'LUNARTEST1', estimate_percent => DBMS_STATS.AUTO_SAMPLE_SIZE,
            method_opt => 'FOR ALL COLUMNS SIZE AUTO');
  Rationale
  ---------
    The optimizer requires up-to-date statistics for the table in order to
    select a good execution plan.
2- SQL Profile Finding (see explain plans section below)
--------------------------------------------------------
  A potentially better execution plan was found for this statement.
  Recommendation (estimated benefit: 91.31%)
  ------------------------------------------
  - Consider accepting the recommended SQL profile.
    execute dbms_sqltune.accept_sql_profile(task_name =>
            'Lunar_tunning_bjgduva68mbqm', task_owner => 'LUNAR', replace =>
            TRUE);
  Validation results
  ------------------
  The SQL profile was tested by executing both its plan and the original plan
  and measuring their respective execution statistics. A plan may have been
  only partially executed if the other could be run to completion in less time.
                           Original Plan  With SQL Profile  % Improved
                           -------------  ----------------  ----------
  Completion Status:            COMPLETE          COMPLETE
  Elapsed Time (s):             .000196            .00002      89.79 %
  CPU Time (s):                   .0002                 0        100 %
  User I/O Time (s):                  0                 0
  Buffer Gets:                       23                 2       91.3 %
  Physical Read Requests:             0                 0
  Physical Write Requests:            0                 0
  Physical Read Bytes:                0                 0
  Physical Write Bytes:               0                 0
  Rows Processed:                     1                 1
  Fetches:                            1                 1
  Executions:                         1                 1
  Notes
  -----
  1. Statistics for the original plan were averaged over 10 executions.
  2. Statistics for the SQL profile plan were averaged over 10 executions.
-------------------------------------------------------------------------------
EXPLAIN PLANS SECTION
-------------------------------------------------------------------------------
1- Original With Adjusted Cost
------------------------------
Plan hash value: 1172089107
--------------------------------------------------------------------------------
| Id  | Operation         | Name       | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |            |     1 |     3 |     7   (0)| 00:00:01 |
|*  1 |  TABLE ACCESS FULL| LUNARTEST1 |     1 |     3 |     7   (0)| 00:00:01 |
--------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
   1 - filter("N"=1)
2- Using SQL Profile
--------------------
Plan hash value: 3241900148
-------------------------------------------------------------------------------------
| Id  | Operation        | Name             | Rows  | Bytes | Cost (%CPU)| Time     |
-------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT |                  |     1 |     3 |     1   (0)| 00:00:01 |
|*  1 |  INDEX RANGE SCAN| IDX_LUNARTEST1_N |     1 |     3 |     1   (0)| 00:00:01 |
-------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
   1 - access("N"=1)
-------------------------------------------------------------------------------
Elapsed: 00:00:00.06
LUNAR@lunardb>
这里我们看到SQL Tuning Advisor提示了两个建议:
1,收集统计信息:
    execute dbms_stats.gather_table_stats(ownname => 'LUNAR', tabname =>
            'LUNARTEST1', estimate_percent => DBMS_STATS.AUTO_SAMPLE_SIZE,
            method_opt => 'FOR ALL COLUMNS SIZE AUTO');
1
.
2,提供了一个执行计划建议:
1
    execute dbms_sqltune.accept_sql_profile(task_name =>
            'Lunar_tunning_bjgduva68mbqm', task_owner => 'LUNAR', replace =>
            TRUE);
并且给出了这个执行计划和原始执行计划的对比,可以看到  执行效率提高了89%以上,逻辑读从23降低为2,减少了91.3%。
.
下面我们按照建议执行。
首先收集统计信息:
LUNAR@lunardb>execute dbms_stats.gather_table_stats(ownname => 'LUNAR', tabname =>'LUNARTEST1', estimate_percent => DBMS_STATS.AUTO_SAMPLE_SIZE, method_opt => 'FOR ALL COLUMNS SIZE AUTO'); PL/SQL procedure successfully completed. Elapsed: 00:00:00.12 LUNAR@lunardb>
然后我们接受建议中的执行计划:
LUNAR@lunardb>execute dbms_sqltune.accept_sql_profile(task_name => 'Lunar_tunning_bjgduva68mbqm', task_owner => 'LUNAR', replace =>TRUE); PL/SQL procedure successfully completed. Elapsed: 00:00:00.33 LUNAR@lunardb>
现在,再次查询看看效果:
LUNAR@lunardb>select /*+ no_index(lunartest1 idx_lunartest1_n) */ * from lunartest1 where n=1;
Elapsed: 00:00:00.08
Execution Plan
----------------------------------------------------------
Plan hash value: 3241900148
-------------------------------------------------------------------------------------
| Id  | Operation        | Name             | Rows  | Bytes | Cost (%CPU)| Time     |
-------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT |                  |     1 |     3 |     1   (0)| 00:00:01 |
|*  1 |  INDEX RANGE SCAN| IDX_LUNARTEST1_N |     1 |     3 |     1   (0)| 00:00:01 |
-------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
   1 - access("N"=1)
Note
-----
   - SQL profile "SYS_SQLPROF_015236655fb80000" used for this statement
Statistics
----------------------------------------------------------
         37  recursive calls
          0  db block gets
         14  consistent gets
          1  physical reads
          0  redo size
        519  bytes sent via SQL*Net to client
        524  bytes received via SQL*Net from client
          2  SQL*Net roundtrips to/from client
          1  sorts (memory)
          0  sorts (disk)
          1  rows processed
这里我们看到,这个执行计划中已经使用了索引,并且逻辑读从49降低为14,
但是这里还有物理读,因此,我们再次执行看看:
LUNAR@lunardb>/
Elapsed: 00:00:00.01
Execution Plan
----------------------------------------------------------
Plan hash value: 3241900148
-------------------------------------------------------------------------------------
| Id  | Operation        | Name             | Rows  | Bytes | Cost (%CPU)| Time     |
-------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT |                  |     1 |     3 |     1   (0)| 00:00:01 |
|*  1 |  INDEX RANGE SCAN| IDX_LUNARTEST1_N |     1 |     3 |     1   (0)| 00:00:01 |
-------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
   1 - access("N"=1)
Note
-----
   - SQL profile "SYS_SQLPROF_015236655fb80000" used for this statement
Statistics
----------------------------------------------------------
          0  recursive calls
          0  db block gets
          3  consistent gets
          0  physical reads
          0  redo size
        519  bytes sent via SQL*Net to client
        524  bytes received via SQL*Net from client
          2  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
          1  rows processed
LUNAR@lunardb>
逻辑读从14降低为3,这个执行计划已经是我们需要的。
现在我们查看一下这个SQL Profile的OUTLINE:
LUNAR@lunardb>SELECT extractValue(value(h),'.') AS hint
  2  FROM sys.sqlobj$data od, sys.sqlobj$ so,
  3  table(xmlsequence(extract(xmltype(od.comp_data),'/outline_data/hint'))) h
  4  WHERE so.name = 'SYS_SQLPROF_015236655fb80000'
  5  AND so.signature = od.signature
  6  AND so.category = od.category
  7  AND so.obj_type = od.obj_type
  8  AND so.plan_id = od.plan_id;
HINT
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
COLUMN_STATS("LUNAR"."LUNARTEST1", "N", scale, length=3 distinct=10000 nulls=0 min=1 max=10000)
TABLE_STATS("LUNAR"."LUNARTEST1", scale, blocks=20 rows=10000)
OPTIMIZER_FEATURES_ENABLE(default)
IGNORE_OPTIM_EMBEDDED_HINTS
Elapsed: 00:00:00.05
LUNAR@lunardb>
这里我们看到该SQP Profile中提供了详细的表和列的统计信息
并且有“IGNORE_OPTIM_EMBEDDED_HINTS”,也就是忽略嵌入到SQL中的hint
结论:
虽然这个SQL的hint中指定了no index,即不使用索引,但是sql语句仍然按照SYS_SQLPROF_015236655fb80000指定的profile使用了index。
说明dbms_sqltune.accept_sql_profile方式绑定的执行计划优先级高于hint指定是否使用索引的方式。
不过不代表所有hint的优先级都低,还需要测试更多其他hint……
 
								 
 
 
 
 
