今天处理了这样一问题,where条件中存在函数fun(date)<to_date('9999-01-01','YYYY-MM-DD')这样的无实际意义谓词,导致CBO计算基数时cardinality远小于实际情况,导致优化器认为2个源数据集的基数都不大,从而选择了HASH JOIN Right SEMI+SORT ORDER BY的执行计划,但是由于实际基数远大于computed 计算值所以变成了大的数据集做HASH JOIN并全数据排序,而实际该SQL只要求返回几十行数据而已,使用NESTED LOOP SEMI JOIN可以立即返回排序的前20行数据。 这里就需要解释带函数的谓词时CBO如何计算基数,我们通过下面的例子来说明:

create or replace function check_date( RDATE in date)  return date is
begin
IF rdate< to_date('2099-01-01','YYYY-MM-DD') then   return rdate;   ELSIF  rdate >=to_date('2099-01-01','YYYY-MM-DD') then return to_date('2000-01-01');end if;end check_date;/SQL> select check_date (sysdate) from dual;CHECK_DAT
---------
06-DEC-12drop table tab1;SQL> create table tab1 tablespace users as select * from dba_objects where rownum create view vtab1 as select object_id as id , object_name as name, object_type as type , check_date(created) cdata from tab1;View created.SQL> select count(distinct cdata) from vtab1;COUNT(DISTINCTCDATA)
--------------------130SQL> exec dbms_stats.gather_table_stats('','TAB1', method_opt=>'FOR ALL COLUMNS SIZE 254');PL/SQL procedure successfully completed.

因为我们指定收集了直方图所以若直接以"created"为条件查询时可以获得较好的计算基数

   SQL> select count(*) from tab1 where  created  >= to_date('0001-10-10','YYYY-MM-DD');COUNT(*)
----------10000Execution Plan
----------------------------------------------------------
Plan hash value: 1117438016---------------------------------------------------------------------------
| Id  | Operation          | Name | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |      |     1 |     8 |    40   (0)| 00:00:01 |
|   1 |  SORT AGGREGATE    |      |     1 |     8 |            |          |
|*  2 |   TABLE ACCESS FULL| TAB1 | 10000 | 80000 |    40   (0)| 00:00:01 |
---------------------------------------------------------------------------Predicate Information (identified by operation id):
---------------------------------------------------2 - filter("CREATED">=TO_DATE(' 0001-10-10 00:00:00', 'syyyy-mm-ddhh24:mi:ss'))Statistics
----------------------------------------------------------1  recursive calls0  db block gets133  consistent gets0  physical reads0  redo size526  bytes sent via SQL*Net to client523  bytes received via SQL*Net from client2  SQL*Net roundtrips to/from client0  sorts (memory)0  sorts (disk)1  rows processed

在以上查询中>= to_date('0001-10-10','YYYY-MM-DD'); 这样的过滤条件实际无意义,在直接使用 "created"列作为谓词的情况下,CBO可以获得很好的基数10000。

SQL> select * from TABLE(dbms_xplan.display_cursor(NULL,NULL,'ALLSTATS LAST'));PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
SQL_ID  6zy2k9dy4cv73, child number 0
-------------------------------------
select /*+ gather_plan_statistics */ count(*) from vtab1 where  cdata
>= to_date('0001-10-10','YYYY-MM-DD')Plan hash value: 1117438016-------------------------------------------------------------------------------------
| Id  | Operation          | Name | Starts | E-Rows | A-Rows |   A-Time   | Buffers |
-------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |      |      1 |        |      1 |00:00:00.25 |     154 |
|   1 |  SORT AGGREGATE    |      |      1 |      1 |      1 |00:00:00.25 |     154 |
|*  2 |   TABLE ACCESS FULL| TAB1 |      1 |    500 |  10000 |00:00:00.31 |     154 |
-------------------------------------------------------------------------------------Predicate Information (identified by operation id):
---------------------------------------------------2 - filter("CHECK_DATE"("CREATED")>=TO_DATE(' 0001-10-10 00:00:00','syyyy-mm-dd hh24:mi:ss'))21 rows selected.

通过gather_plan_statistics HINT,我们得到E-Rows 即CBO评估的基数,和 A-Rows实际的基数,可以看到这里E-Rows=500, 即在谓词左边存在使用内部函数或隐身装换的情况下,CBO无法通过现有统计信息的DISTINCT、DENSITY和HISTOGRAM获得较好的Cardinality,其基数总是统计信息中表的总行数/20,如上例中的 10000/20=500。 这就会引入不少的麻烦,因为开发人员有时候为了方便会在视图字段中嵌入自定义的函数,之后若在查询中使用该字段作为谓词条件,则可能导致CBO为相应表计算的基数偏少,是本身应当成本非常高的执行计划的COST变低,而容易被优化器选择。 对于上述问题可选的常见方案是若有这样问题的SQL较少则考虑加HINT或者SQL PROFILE,若较多还是需要考虑减少这种谓词左边有函数的现象。 implicit data_type conversion functions in Filter Predicates. Review Execution Plans. If Filter Predicatesinclude unexpected INTERNAL_FUNCTION to perform an implicit data_type conversion, be sure it is not preventing a column from being used as an Access Predicate.

转载于:https://www.cnblogs.com/macleanoracle/archive/2013/03/19/2968127.html

SQL调优:带函数的谓词导致CBO Cardinality计算误差相关推荐

  1. 这些SQL调优小技巧,你学废了吗?

    推荐:本文转载自"老虎刘".敢于对技术网红文提出质疑,并给出有效评论和批复,刘哥走在了我们前面. Oracle 原厂优化组组长,严谨治学,敬畏技术,在刘哥身上,你可以看到热情,热血 ...

  2. SQL调优指南笔记6:Explaining and Displaying Execution Plans

    本文为SQL Tuning Guide第6章"解释和显示执行计划"的笔记. 了解如何解释SQL语句并显示其计划对于 SQL 调优至关重要. 重要基本概念 row source tr ...

  3. oracle sql 执行计划分析_Oracle SQL调优系列之看懂执行计划explain

    1.文章写作前言简介 SQL调优系列博客链接:SQL调优专栏 之前曾经拜读过<收获,不止sql调优>一书,此书是国内DBA写的一本很不错的调优类型的书,是一些很不错的调优经验的分享.虽然读 ...

  4. SQL调优指南笔记19:Influencing the Optimizer

    本文为SQL Tuning Guide第19章"Influencing the Optimizer"的笔记. 重要基本概念 driving table The table to w ...

  5. oracle trim 性能,ORACLE sql调优之记录一次trim函数引发的大表全表扫描

    2017年8月14日,一地市oracle相关的调度程序ETL抽取速度奇慢,sql语句每次执行平均时间要9秒左右,如果所示: 该调度过程涉及的sql语句如下: select count(*) from ...

  6. Oracle Hints,Oracle并行模式(Parallel) /*+parallel(t,4)*/ 在SQL调优中的重要作用

    /*+parallel(t,4)*/在SQL调优中的重要作用! 2013年11月17日 12:59:24 雾里看花5566 阅读数:5422更多 个人分类: 数据库-oracle 谈谈HINT /*+ ...

  7. MySQL 索引和 SQL 调优手册

    MySQL索引 MySQL支持诸多存储引擎,而各种存储引擎对索引的支持也各不相同,因此MySQL数据库支持多种索引类型,如BTree索引,哈希索引,全文索引等等.为了避免混乱,本文将只关注于BTree ...

  8. MySQL索引和SQL调优手册

    MySQL索引 MySQL支持诸多存储引擎,而各种存储引擎对索引的支持也各不相同,因此MySQL数据库支持多种索引类型,如BTree索引,哈希索引,全文索引等等. 为了避免混乱,本文将只关注于BTre ...

  9. sql调优的几种方式_「数据库调优」屡试不爽的面试连环combo

    点赞再看,养成习惯,微信搜索[三太子敖丙]关注这个互联网苟且偷生的工具人. 本文 GitHub https://github.com/JavaFamily 已收录,有一线大厂面试完整考点.资料以及我的 ...

最新文章

  1. json_decode的结果是null
  2. 需求调研计划_拆书营销管理 实施营销调研和预测需求
  3. getInitParameter方法
  4. 解决springboot不扫描@repository的问题
  5. sicp第一章部分习题解答
  6. php变量教学,PHP变量详解
  7. 如何让火狐浏览器兼容window.event
  8. Spring知识点总结-3
  9. python解释器的使用
  10. Linux shell 查找操作
  11. CoppeliaSim(vrep)弹簧模型
  12. ubuntu下将eth3改为eth0及HWaddr的修改
  13. 计算机硬件技术的应用毕业论文,计算机应用毕业论文.计算机分类和硬件技术发展状况.doc...
  14. 大咖说开源|郑振宇:通过开源手段巩固基础软件供应链
  15. java语言中标识符大小写不敏感_下列叙述中,正确的是()。A.Java语言的标识符是区分大小写的B.源文件名与public类名可...
  16. 【Python】—— pipenv使用小结
  17. ECharts-中国省市地图
  18. 最佳实践 | 如何提高落地页的转化率?这里有4个策略
  19. echart旭日图_基于Echarts4.0实现旭日图
  20. PGL图学习之图神经网络ERNIESage、UniMP进阶模型[系列八]

热门文章

  1. 好分数阅卷3.0_自考通过率低?一位资深阅卷老师的自述
  2. 数据库知识:SQLServer变量相关知识介绍
  3. 后端:Java中的BigDecimal类你了解多少?
  4. 通俗易懂,一篇文章告诉你编程语言是个啥?
  5. Shell重定向的概念笔记
  6. 某游戏在华为鸿蒙,华为鸿蒙系统运行安卓游戏出现新状况!安卓换皮论被彻底打脸?...
  7. Docker---问题1:bash: vi: command not found/bash: vim: command not found
  8. 同时获取同一等级下多个class值的节点的方法
  9. 幕后常驻嘉宾配音小姐姐的2021年度总结
  10. 入坑 Electron 开发跨平台桌面应用