测试目的,当有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……