Oracle12c中的自适应查询优化有一系列不同特点组成。像自适应计划(AdaptivePlans)功能可以在运行时修改执行计划,但并不允许计划中连接顺序的改变。自动重优化基于先前执行和反馈到优化器信息的学习,因此,语句下次解析执行时将会生成一个较好的计划。

1.   统计信息反馈(势反馈)

势反馈(Cardinalityfeedback)在Oracle11r2中被引进。当优化器产生一个执行计划时,统计信息缺失、统计信息陈旧、复杂谓词或复杂操作等也许会触发优化器监视计划中各个操作的势。一旦执行完成,如果评估和实际势之间差别较大,实际势将会被存在SGA中以备今后使用,且该语句也被标作可重优化。该语句下次执行时会采用存储的势来进行重优化,以便采用较好的计划。势反馈是语句确定的,且实例重启或共享池中的语句陈旧时会丢失。Oracle12c中,势反馈已经重命名为统计信息反馈。

--注:

1)   统计信息反馈相关信息在SGA中作为V$SQL_REOPTIMIZATION_HINTS 视图中的OPT_ESTIMATE hints 存储。该视图和hints未被归档。

1.1.  示例

下面的代码创建一个管道表函数,通过它说明统计信息反馈

CONN test1/test@pdb1
-- 创建支持表函数的类型
DROP TYPE tp_tf_tab;
DROP TYPE tp_tf_row;
CREATE TYPE tp_tf_row AS OBJECT (
  id           NUMBER,
  description  VARCHAR2(50)
);
/
 
CREATE TYPE tp_tf_tab IS TABLE OF tp_tf_row;
/
 
-- 创建表函数.
CREATE OR REPLACE FUNCTION f_tab_pl (p_rows IN NUMBER) RETURN tp_tf_tabPIPELINED AS
BEGIN
  FOR i IN 1 .. p_rows LOOP
    PIPE ROW (tp_tf_row(i,'Description for ' || i));
  END LOOP;
  RETURN;
END;
/
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.

我们知道,优化器总是基于数据库块大小来评估管道表函数的势,因此,我们希望得到该管道函数查询势的一个错误评估。下面的查询返回10行数据,但优化器评估出了8168行,这显然是错误的。

SELECT /*+ GATHER_PLAN_STATISTICS */ * FROM TABLE(f_tab_pl(10));
 
SET LINESIZE 200 PAGESIZE 100
SELECT * FROM TABLE(DBMS_XPLAN.display_cursor(format => 'allstatslast'));
PLAN_TABLE_OUTPUT
-------------------------------------------------------------------------------------------------
SQL_ID  0ktmsgvczysxy, child number0
-------------------------------------
SELECT /*+ GATHER_PLAN_STATISTICS */ * FROM TABLE(f_tab_pl(10))
Plan hash value: 822655197
-------------------------------------------------------------------------------------------------
| Id  | Operation                         | Name        | Starts | E-Rows | A-Rows |   A-Time  |
-------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                  |             |      1 |       |     10 |00:00:00.01 |
|   1 |  COLLECTION ITERATOR PICKLER FETCH|F_TAB_PL    |      1 |  8168 |     10 |00:00:00.01 |
-------------------------------------------------------------------------------------------------
SQL>
检查视图列V$SQL.IS_REOPTIMIZABLE显示优化器已经探测到了不正确的势评估并把该语句标示为将被重新优化。
COLUMN sql_text FORMAT A50
COLUMN is_reoptimizable FORMAT A16
SELECT sql_text, is_reoptimizable
FROM   v$sql
WHERE  sql_text LIKE '%f_tab_pl%'
AND    sql_text NOT LIKE '%v$sql%';
SQL_TEXT                                          IS_REOPTIMIZABLE
-------------------------------------------------- ----------------
SELECT /*+ GATHER_PLAN_STATISTICS */       * FROM Y
   TABLE(f_tab_pl(10))
SQL>
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.

如果再次运行该语句,我们将看到更精确的一个势评估,且有个注意部分告诉我们采用了统计信息反馈。同时,也注意到子游标号也发生了改变。

SELECT /*+ GATHER_PLAN_STATISTICS */ * FROM   TABLE(f_tab_pl(10));
SET LINESIZE 200 PAGESIZE 100
SELECT * FROM TABLE(DBMS_XPLAN.display_cursor(format => 'allstatslast'));
PLAN_TABLE_OUTPUT
-------------------------------------------------------------------------------------------------
SQL_ID  0ktmsgvczysxy, child number1
-------------------------------------
SELECT /*+ GATHER_PLAN_STATISTICS */       * FROM
TABLE(f_tab_pl(10))
Plan hash value: 822655197
-------------------------------------------------------------------------------------------------
| Id  | Operation                         | Name        | Starts | E-Rows | A-Rows |   A-Time  |
-------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                  |             |      1 |       |     10 |00:00:00.01 |
|   1 |  COLLECTION ITERATOR PICKLER FETCH|F_TAB_PL    |      1 |    20 |     10 |00:00:00.01 |
-------------------------------------------------------------------------------------------------
Note
-----
   - statistics feedback used forthis statement
SQL>
--注:
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.

1)   11Rr2版本中,注意部分将会是"cardinality feedbackused for this statement"。

2)   文档中也提到,势的错误评估也会导致生成SQL计划指令(SQLplan directives) ,但不要误以为统计信息反馈被保留在SQL计划指令中。我们可以通过如下语句查询SQL计划指令是否存在。

CONN sys@pdb1 AS SYSDBA
EXEC DBMS_SPD.flush_sql_plan_directive;
SET LINESIZE 200
COLUMN dir_id FORMAT A20
COLUMN owner FORMAT A10
COLUMN object_name FORMAT A10
COLUMN col_name FORMAT A10
 
SELECT TO_CHAR(d.directive_id) dir_id, o.owner, o.object_name, 
       o.subobject_name col_name,o.object_type, d.type, d.state, d.reason
FROM   dba_sql_plan_directives d,dba_sql_plan_dir_objects o
WHERE  d.directive_id=o.directive_id
AND    o.owner = 'TEST'
ORDER BY 1,2,3,4,5;
 
no rows selected
SQL>
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.

2.   性能反馈(Performance Feedback)

Oracle 11gR2引进了PARALLEL_DEGREE_POLICY初始化参数用以简化并行查询。该参数默认值为MANUAL,当被设置为AUTO时,能使并行度确定,语句排队和内存内并行执行自动化。

Oracle 12cR1为该参数增加了ADAPTIVE设置,该值类似于AUTO,但包括了性能反馈。这种情况下,优化器决定语句是否并行运行和合适的并行度。当完成时,会对语句的实际性能和初始优化阶段的评估性能进行对比。如果两者间差别很大,则实际性能统计信息被存储为统计信息反馈,且语句也被标为可重新优化的。当该语句下次被执行时,统计信息反馈会被用来选择一个更合适的并行度(DOP)。

--注:

1)   从Oracle 11gR2向后,语句中的PARALLEL hint将导致系统自动选择并行度,而不管PARALLEL_DEGREE_POLICY设置为什么值。

3.   统计信息反馈和SQL计划指令(相互作用)

该部分大多基于我对统计信息反馈的经验推测。先前我们做测试的语句并不会保存为SQL计划指令。统计信息反馈指示优化器已经做了不好的选择,这些选择一般是因为确定执行计划时缺失重要的信息。统计信息反馈能被用于重优化,但它并不解决最初的问题。基本统计信息还是不具有代表性。

SQL计划指令是“额外提示”,能阻止优化器在将来犯同样的错误。在有些场景,自动重优化也会导致生成SQL计划执行,但这并不包括统计信息反馈和性能反馈,而是执行动态采样来解决短期内偏离问题,因此,不再需要统计信息反馈。

由于SQL计划指令影响DBMS_STATS包未来收集统计信息的方式,因此,通过为基础统计信息添加另外的信息(扩展统计信息),它有能力从根本上解决问题,从而使不再需要SQL计划执行和统计信息反馈。一个需要统计信息反馈的场景也许会生成SQL计划指令,但那并不意味着SQL计划指令包含统计信息反馈的一个可保留版本。

当统计信息反馈和SQL计划指令因势错误评估而都被创建时,在两者间有些很有意思的相互作用:

Ø 两者都被在SGA中创建但SQL计划指令还未被保留到SYSAUX表空间的场景中,统计信息反馈在重优化期间被使用,期间忽视SQL计划指令的存在。

Ø 两者都被创建但SQL计划指令被保留到SYSAUX表空间的场景,SQL计划指令在重优化期间被使用,统计信息反馈也可能被使用。

由于SQL计划指令仅仅被周期性的保留,这意味着依赖于SQL语句第一次和第二次执行间时间的长短,最后的重优化可能是完全不同的,这导致结果的不可预测。