专栏首页Oracle数据库技术基数反馈 (Cardinality Feedback)(二)

基数反馈 (Cardinality Feedback)(二)

概述

本文为基数反馈(Cardinality Feedback 以后简称CFB)功能的第二部分,主要介绍CFB有效时的状况例子,以及CFB处理流程。

关于CFB无效时的状况例子,以及CFB概述请参考前篇文章:

基数反馈 (Cardinality Feedback)(一)

例子2(CFB有效)

下面我们在11.2.0.4的环境中也就是CFB有效的情况下,看看执行的情况: (我们依然使用Oracle数据库提供的样例Schema OE 及其表PRODUCT_INFORMATION和ORDER_ITEMS进行测试。)

1.首先确认相关表的统计信息和表的数据量。(基于11.2.0.4版本测试)

--统计信息能够反映出表中的数据量。
    SQL> select TABLE_NAME,NUM_ROWS,BLOCKS from user_tables where TABLE_NAME in ('PRODUCT_INFORMATION','ORDER_ITEMS');

TABLE_NAME             NUM_ROWS     BLOCKS 
-------------------- ---------- ---------- 
ORDER_ITEMS                 665          5 
PRODUCT_INFORMATION         288         13 

Elapsed: 00:00:00.04
SQL> select count(*) from ORDER_ITEMS;

  COUNT(*)
----------
       665

Elapsed: 00:00:00.02
SQL> select count(*) from PRODUCT_INFORMATION;

  COUNT(*)
----------
       288

Elapsed: 00:00:00.01
SQL> 

2.设定环境参数statistics_level为ALL,以便能够通过dbms_xplan.display_cursor函数查看SQL文根据统计信息估算出的访问数据行数和SQL执行时的实际值。

SQL> alter session set statistics_level=all;

Session altered.

Elapsed: 00:00:00.01

3.第一次执行SQL文

SQL> 
SQL> SELECT  o.order_id, v.product_name
  2  FROM   orders o,
  3         ( SELECT order_id, product_name
  4           FROM   order_items o, product_information p
  5           WHERE  p.product_id = o.product_id
  6           AND    list_price < 50
  7           AND    min_price < 40 ) v
  8  WHERE  o.order_id = v.order_id
  9  ;

  ORDER_ID PRODUCT_NAME                                     
---------- --------------------                             
      2403 Battery - EL                                     
...
      2450 Plastic Stock - W/HD                             

269 rows selected.

Elapsed: 00:00:00.22
SQL> 

4.查看第一次执行后的执行计划。

SQL> select * from table(dbms_xplan.display_cursor(format=>'typical iostats last -cost -bytes'));

PLAN_TABLE_OUTPUT                                           
---------------------------------------------------------------------------------------------
SQL_ID  bmh5hb8331u33, child number 0                       
-------------------------------------                       
SELECT  o.order_id, v.product_name FROM   orders o,        ( SELECT        ...                                                             
o.order_id = v.order_id                                     

Plan hash value: 1906736282                                 

---------------------------------------------------------------------------------------------------------------------------       
| Id  | Operation             | Name                | Starts | E-Rows | E-Time   | A-Rows |   A-Time   | Buffers | Reads  |       
---------------------------------------------------------------------------------------------------------------------------       
|   0 | SELECT STATEMENT      |                     |      1 |        |          |    269 |00:00:00.17 |    1337 |     20 |       
|   1 |  NESTED LOOPS         |                     |      1 |      1 | 00:00:01 |    269 |00:00:00.17 |    1337 |     20 |       
|   2 |   MERGE JOIN CARTESIAN|                     |      1 |      4 | 00:00:01 |   9135 |00:00:00.06 |      33 |     15 |       
|*  3 |    TABLE ACCESS FULL  | PRODUCT_INFORMATION |      1 |   ★ 1 | 00:00:01 |  ★ 87 |00:00:00.01 |      32 |     14 |       
|   4 |    BUFFER SORT        |                     |     87 |    105 | 00:00:01 |   9135 |00:00:00.02 |       1 |      1 |       
|   5 |     INDEX FULL SCAN   | ORDER_PK            |      1 |    105 | 00:00:01 |    105 |00:00:00.01 |       1 |      1 |       
|*  6 |   INDEX UNIQUE SCAN   | ORDER_ITEMS_UK      |   9135 |      1 |          |    269 |00:00:00.05 |    1304 |      5 |       
---------------------------------------------------------------------------------------------------------------------------       

Predicate Information (identified by operation id):         
---------------------------------------------------         

   3 - filter(("MIN_PRICE"<40 AND "LIST_PRICE"<50))         
   6 - access("O"."ORDER_ID"="ORDER_ID" AND "P"."PRODUCT_ID"="O"."PRODUCT_ID")                                                    


28 rows selected.

Elapsed: 00:00:00.19

我们发现和10.2.0.5环境一样,由于访问条件(“MIN_PRICE”<40 AND “LIST_PRICE”<50)的影响,优化器认为PRODUCT_INFORMATION表的预估行数(E-Rows)为1,优化器基于预估基数在选择表PRODUCT_INFORMATION和ORDER_ITEMS结合的最优执行计划时,选择了MERGE JOIN CARTESIAN的结合方式。

5.查看动态视图V$sql和v$SQL_SHARED_CURSOR

SQL> ---sql_id:bmh5hb8331u33
SQL> select sql_id,child_number, executions, buffer_gets,plan_hash_value
  2  from v$sql
  3  where sql_id = 'bmh5hb8331u33';

SQL_ID        CHILD_NUMBER EXECUTIONS BUFFER_GETS PLAN_HASH_VALUE
------------- ------------ ---------- ----------- ---------------
bmh5hb8331u33            0          1        1604      1906736282

Elapsed: 00:00:00.01
SQL> 
SQL> select sql_id, child_number, USE_FEEDBACK_STATS
  2  from V$SQL_SHARED_CURSOR
  3  where sql_id = 'bmh5hb8331u33';

SQL_ID        CHILD_NUMBER U                                
------------- ------------ -                                
bmh5hb8331u33            0 Y                                

Elapsed: 00:00:00.04
SQL> 

我们发现V$SQL_SHARED_CURSOR的USE_FEEDBACK_STATS列标记为Y。 (USE_FEEDBACK_STATS列是在11.2.0.4 的版本上新追加的列,用于标示当根据统计信息估算出的基数(Computed cardinality)和SQL执行时的实际值差距很大时,下次执行时重新生成执行计划)

6.我们再次次执行相同的SQL文

---第二次执行
SQL> SELECT  o.order_id, v.product_name
...
  8  WHERE  o.order_id = v.order_id
  9  ;

SQL> 

7.再次查看执行计划

SQL> select * from table(dbms_xplan.display_cursor(format=>'typical iostats last -cost -bytes'));

PLAN_TABLE_OUTPUT                                           
---------------------------------------------------------------------------------------------
SQL_ID  bmh5hb8331u33, child number 1                       
-------------------------------------                       
SELECT  o.order_id, v.product_name FROM   orders o,        ( SELECT
order_id, product_name          FROM   order_items o,       
product_information p          WHERE  p.product_id = o.product_id
   AND    list_price < 50          AND    min_price < 40 ) v WHERE
o.order_id = v.order_id                                     

Plan hash value: 35479787                                   

----------------------------------------------------------------------------------------------------------------------------      
| Id  | Operation              | Name                | Starts | E-Rows | E-Time   | A-Rows |   A-Time   | Buffers | Reads  |      
----------------------------------------------------------------------------------------------------------------------------      
|   0 | SELECT STATEMENT       |                     |      1 |        |          |    269 |00:00:00.01 |      61 |      1 |      
|   1 |  NESTED LOOPS          |                     |      1 |    313 | 00:00:01 |    269 |00:00:00.01 |      61 |      1 |      
|*  2 |   HASH JOIN            |                     |      1 |    313 | 00:00:01 |    269 |00:00:00.01 |      40 |      1 |      
|*  3 |    TABLE ACCESS FULL   | PRODUCT_INFORMATION |      1 |     ★87 | 00:00:01 |     ★87 |00:00:00.01 |      15 |      0 |      
|   4 |    INDEX FAST FULL SCAN| ORDER_ITEMS_UK      |      1 |    665 | 00:00:01 |    665 |00:00:00.01 |      25 |      1 |      
|*  5 |   INDEX UNIQUE SCAN    | ORDER_PK            |    269 |      1 |          |    269 |00:00:00.01 |      21 |      0 |      
----------------------------------------------------------------------------------------------------------------------------      

Predicate Information (identified by operation id):         
---------------------------------------------------         

   2 - access("P"."PRODUCT_ID"="O"."PRODUCT_ID")            
   3 - filter(("MIN_PRICE"<40 AND "LIST_PRICE"<50))         
   5 - access("O"."ORDER_ID"="ORDER_ID")                    

Note                                                        
-----                                                       
   - cardinality feedback used for this statement     ★      


32 rows selected.

Elapsed: 00:00:00.03

我们发现SQL文进行了硬解析,并且表PRODUCT_INFORMATION的预估信息(E-Rows)调整为第一次执行时收集的实际值(87),用于优化器选择执行计划。因此,优化器基于调整后预估基数在选择表PRODUCT_INFORMATION和ORDER_ITEMS结合的最优执行计划时,选择了HASH JOIN的结合方式,从而更有效的执行了SQL文。

8.再次查看动态视图V和SQL_SHARED_CURSOR

SQL> ---sql_id:bmh5hb8331u33
SQL> select sql_id,child_number, executions, buffer_gets,plan_hash_value,is_shareable
  2  from v$sql
  3  where sql_id = 'bmh5hb8331u33';

SQL_ID        CHILD_NUMBER EXECUTIONS BUFFER_GETS PLAN_HASH_VALUE I
------------- ------------ ---------- ----------- --------------- -
bmh5hb8331u33            0          1        1604      1906736282 N★
bmh5hb8331u33            1          1          61        35479787 Y★

Elapsed: 00:00:00.02
SQL> 
SQL> select sql_id, child_number, USE_FEEDBACK_STATS
  2  from V$SQL_SHARED_CURSOR
  3  where sql_id = 'bmh5hb8331u33';

SQL_ID        CHILD_NUMBER U
------------- ------------ -
bmh5hb8331u33            0 Y
bmh5hb8331u33            1 N

Elapsed: 00:00:00.00

通过视图V$SQL我们发现,新生成的游标CHILD#1比以前的游标CHILD#1会使用更少的BUFFER_GETS,效率更高。并且以前游标CHILD#0的is_shareable列标记为N,不在被共享。 新生成的游标CHILD#1的is_shareable列标记为Y,供以后的执行重用。

9.再多次执行SQL文

--第三次执行
SQL> SELECT  o.order_id, v.product_name
...
  8  WHERE  o.order_id = v.order_id
  9  ;

--第四次执行
SQL> SELECT  o.order_id, v.product_name
...
  8  WHERE  o.order_id = v.order_id
  9  ;

  ORDER_ID PRODUCT_NAME     
---------- --------------------                             
      2403 Battery - EL     
...
      2401 SPNIX3.3 AU      

269 rows selected.

Elapsed: 00:00:00.05
SQL> 
 --查看执行计划
SQL> set line 200
SQL> set pagesize 9999
SQL> 
SQL> select * from table(dbms_xplan.display_cursor(format=>'typical iostats last -cost -bytes'));

PLAN_TABLE_OUTPUT           
---------------------------------------------------------------------------------------------
SQL_ID  bmh5hb8331u33, child number 1                       
-------------------------------------                       
...

Note                        
-----                       
   - cardinality feedback used for this statement           


32 rows selected.

Elapsed: 00:00:00.02
SQL> 
--查看动态视图
SQL> 
SQL> ---sql_id:bmh5hb8331u33
SQL> select sql_id,child_number, executions, buffer_gets,plan_hash_value,is_shareable
  2  from v$sql
  3  where sql_id = 'bmh5hb8331u33';

SQL_ID        CHILD_NUMBER EXECUTIONS BUFFER_GETS PLAN_HASH_VALUE I
------------- ------------ ---------- ----------- --------------- -
bmh5hb8331u33            0          1        1604      1906736282 N
bmh5hb8331u33            1          3         183        35479787 Y

Elapsed: 00:00:00.00
SQL> 
SQL> select sql_id, child_number, USE_FEEDBACK_STATS
  2  from V$SQL_SHARED_CURSOR
  3  where sql_id = 'bmh5hb8331u33';

SQL_ID        CHILD_NUMBER U
------------- ------------ -
bmh5hb8331u33            0 Y
bmh5hb8331u33            1 N

Elapsed: 00:00:00.00

我们发现以后的执行都会变成软解析,使用第二次产生的执行计划。 通过CFB功能使优化器能够在以后的执行中选择更优的执行计划,从得到更好的执行效率。

CFB的处理流程

下面通过以下流程图来总体的回顾一下CFB的处理过程。

在下列情况CBO可能无法估算出准确的Cardinality,Oracle会启用CFB功能:

 ・没有收集表的统计信息,并且dynamic sampling 也没有开启;
 ・ 一个表的查询条件涉及多列,但却没有收集扩展的统计信息(extended statistics)
 ・ 查询条件复杂(比如条件有函数)

针对上述情况,Oracle会采取如下的CFB流程处理:

1. SQL文第一次执行时,Oracle会监控操作的实际行数(A-Row),然后对比CBO估算的行数(E-Row)。
2. 如果两个值相差很大,就记录实际行数(A-Row),做上标记。
    下次执行时再次进行硬解析,根据实际行数来重新生成执行计划。
3. 如果两个值相差不大,CBO就不再监控这条SQL语句。

针对版本12c的一些情况我们将在以后的章节中进行介绍。

参考

https://blogs.oracle.com/optimizer/entry/cardinality_feedback

Cardinality Feedback

Statistics (Cardinality) Feedback - Frequently Asked Questions (Doc ID 1344937.1)

本文分享自微信公众号 - Oracle数据库技术(TeacherWhat)

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2016-06-13

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Oracle优化器之自适应执行计划(Adaptive Execution Plans)

    我们知道在12c之前的版本,虽然有ACS、CFB等功能通过在SQL文执行时收集信息,来改善SQL文再次执行时的执行计划,但是在SQL文第一次执行时,只能根据统计...

    TeacherWhat
  • 基数反馈 (Cardinality Feedback)(一)

    本文将介绍在11gR2的版本上推出了基数反馈(Cardinality Feedback 以后简称CFB)功能,通过这个特性, 对于某些查询在第一次执行时,如果...

    TeacherWhat
  • 【怎么办】003 如何加强Oracle数据库安全--监控数据导入导出操作

    关键字(Keyword):datapummp,audit,unified audit,trigger,触发器,审计,数据库安全

    TeacherWhat
  • 灌入大量数据后手工采集统计信息的重要性

    SQL> create table TBL_STAT as select * from dba_objects where 1<>1; Table creat...

    bisal
  • The SQL vs NoSQL Difference: MySQL vs MongoDB

    在选择数据库时,最大的决策之一是选择关系(SQL)或非关系(NoSQL)数据结构。虽然两者都是可行的选择,但在做出决定时必须牢记两者之间存在某些关键差异。

    银河1号
  • 用人话讲django结合celery实现定时任务

    6.登录 django 的 admin 后台,配置定时任务,选择 Periodic tasks

    用户4945346
  • DApp能否可以挑战中心化应用?别着急,且呢

    区块链大本营
  • django+redis+celery构建实时异步任务调度系统

    3、创建一个项目:django-admin startproject celerydemo

    菲宇
  • android 资源文字ids的作用

    ids.xml——为应用的相关资源提供唯一的资源id。id是为了获得xml中的对象而需要的参数,也就是Object = findViewById(R.id.id...

    xiangzhihong
  • 程序员C语言快速上手——基础篇(五)

    C语言中的函数其实是多条指令的组合单元。更通俗的说就是许多语句的组合单元。函数的好处是可以让编程结构化,而不是像早期的程序那样写成一坨。另外函数可以复用代码,这...

    arcticfox

扫码关注云+社区

领取腾讯云代金券