这篇文章《这条SQL的索引,你会如何创建?》发出后,不少朋友留言,包括一些前辈,指出了其中存在的问题,需要纠正和说明。

问题1,部分截图中有递归调用,这样算一致性读,不准确?

SQL执行计划中的统计信息部分,出现不为0的recursive calls,对结果的判断,究竟有什么影响?

说到这,首先就要了解,什么是递归调用,recursive calls?

Oracle官方文档的解释,

Sometimes, to execute a SQL statement issued by a user, Oracle Database must issue additional statements. Such statements are called recursive calls or recursive SQL statements. For example, if you insert a row into a table that does not have enough space to hold that row, then Oracle Database makes recursive calls to allocate the space dynamically. Recursive calls are also generated when data dictionary information is not available in the data dictionary cache and must be retrieved from disk.

Note: Recursive SQL statistics are not included for SQL-level operations.

大致意思是,有时,用户执行一条SQL语句的时候,Oracle必须调用其他的语句,这些额外调用的语句,就称为"recursive calls",或者"recursive SQL statements",Sometimes,有时会,有时不会,他举了两个例子,当插入记录的时候,没空间容纳这行,此时Oracle就会通过递归调用动态分配空间,另外当数据字典缓存中无法得到需要的数据字典信息时,必须从磁盘读取,此时就会执行递归调用。SQL级别的执行,不包括递归调用执行的SQL统计信息。

IBM的手册中,讲了递归调用的触发条件,

http://publib.boulder.ibm.com/tividd/td/ITMD/SC23-4724-00/en_US/HTML/oraclepac510rg59.htm

  • An object requiring an additional extent for storage (dynamic extension),动态扩展分配额外的空间存储对象

  • Misses on the dictionary cache,数据字典缓存缺少需要的信息

  • Firing of database triggers,数据库触发器

  • DDL statements,DDL语句

  • Execution of SQL statements within stored procedures, packages, functions, and anonymous PL/SQL blocks,在存储过程、包、函数和匿名PL/SQL块中执行SQL语句

  • Enforcement of referential integrity constraints,执行外键完整性约束

针对我们的测试,不同的场景,每个语句首次执行的时候,都可能出现从磁盘读取数据字典信息的需求,但正如上面说的,这种recursive calls是Oracle为了满足用户检索的需求,额外调用的语句,如果比较的是不同SQL本身的性能消耗,公平起见,就需要忽略这些recursive calls。

因此,每个场景,都取第二次执行的统计信息,这种比较,才是更公平的。

重建测试场景,这是未建任何索引的时候,相关的成本消耗,此时recursive calls是0,

SQL> select max(object_id) from t where owner='SYS';Execution Plan
----------------------------------------------------------
Plan hash value: 2966233522---------------------------------------------------------------------------
| Id  | Operation          | Name | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |      |     1 |    30 |    13   (0)| 00:00:01 |
|   1 |  SORT AGGREGATE    |      |     1 |    30 |            |          |
|*  2 |   TABLE ACCESS FULL| T    |  9165 |   268K|    13   (0)| 00:00:01 |
---------------------------------------------------------------------------Predicate Information (identified by operation id):
---------------------------------------------------2 - filter("OWNER"='SYS')Note
------ dynamic sampling used for this statement (level=2)Statistics
----------------------------------------------------------0  recursive calls0  db block gets40  consistent gets0  physical reads0  redo size534  bytes sent via SQL*Net to client524  bytes received via SQL*Net from client2  SQL*Net roundtrips to/from client0  sorts (memory)0  sorts (disk)1  rows processed

方案1,object_id单键值索引,

SQL> select max(object_id) from t where owner='SYS';Execution Plan
----------------------------------------------------------
Plan hash value: 2966233522---------------------------------------------------------------------------
| Id  | Operation          | Name | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |      |     1 |    30 |    13   (0)| 00:00:01 |
|   1 |  SORT AGGREGATE    |      |     1 |    30 |            |          |
|*  2 |   TABLE ACCESS FULL| T    |  9165 |   268K|    13   (0)| 00:00:01 |
---------------------------------------------------------------------------Predicate Information (identified by operation id):
---------------------------------------------------2 - filter("OWNER"='SYS')Note
------ dynamic sampling used for this statement (level=2)Statistics
----------------------------------------------------------0  recursive calls0  db block gets40  consistent gets0  physical reads0  redo size534  bytes sent via SQL*Net to client524  bytes received via SQL*Net from client2  SQL*Net roundtrips to/from client0  sorts (memory)0  sorts (disk)1  rows processed

方案2,owner单键值索引,

SQL> select max(object_id) from t where owner='SYS';Execution Plan
----------------------------------------------------------
Plan hash value: 2966233522---------------------------------------------------------------------------
| Id  | Operation          | Name | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |      |     1 |    30 |    13   (0)| 00:00:01 |
|   1 |  SORT AGGREGATE    |      |     1 |    30 |            |          |
|*  2 |   TABLE ACCESS FULL| T    |  9165 |   268K|    13   (0)| 00:00:01 |
---------------------------------------------------------------------------Predicate Information (identified by operation id):
---------------------------------------------------2 - filter("OWNER"='SYS')Note
------ dynamic sampling used for this statement (level=2)Statistics
----------------------------------------------------------0  recursive calls0  db block gets40  consistent gets0  physical reads0  redo size534  bytes sent via SQL*Net to client524  bytes received via SQL*Net from client2  SQL*Net roundtrips to/from client0  sorts (memory)0  sorts (disk)1  rows processed

方案3,(object_id, owner)复合索引,

SQL> select max(object_id) from t where owner='SYS';Execution Plan
----------------------------------------------------------
Plan hash value: 2966233522---------------------------------------------------------------------------
| Id  | Operation          | Name | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |      |     1 |    30 |    13   (0)| 00:00:01 |
|   1 |  SORT AGGREGATE    |      |     1 |    30 |            |          |
|*  2 |   TABLE ACCESS FULL| T    |     1 |    30 |    13   (0)| 00:00:01 |
---------------------------------------------------------------------------Predicate Information (identified by operation id):
---------------------------------------------------2 - filter("OWNER"='SYS')Note
------ dynamic sampling used for this statement (level=2)Statistics
----------------------------------------------------------0  recursive calls0  db block gets40  consistent gets0  physical reads0  redo size534  bytes sent via SQL*Net to client524  bytes received via SQL*Net from client2  SQL*Net roundtrips to/from client0  sorts (memory)0  sorts (disk)1  rows processed

方案4,(owner, object_id)复合索引,

SQL> select max(object_id) from t where owner='SYS';Execution Plan
----------------------------------------------------------
Plan hash value: 2574007102-----------------------------------------------------------------------------------------
| Id  | Operation                    | Name     | Rows  | Bytes | Cost (%CPU)| Time     |
-----------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT             |          |     1 |    30 |     2   (0)| 00:00:01 |
|   1 |  SORT AGGREGATE              |          |     1 |    30 |            |          |
|   2 |   FIRST ROW                  |          |     1 |    30 |     2   (0)| 00:00:01 |
|*  3 |    INDEX RANGE SCAN (MIN/MAX)| IDX_T_01 |     1 |    30 |     2   (0)| 00:00:01 |
-----------------------------------------------------------------------------------------Predicate Information (identified by operation id):
---------------------------------------------------3 - access("OWNER"='SYS')Note
------ dynamic sampling used for this statement (level=2)Statistics
----------------------------------------------------------0  recursive calls0  db block gets2  consistent gets0  physical reads0  redo size534  bytes sent via SQL*Net to client524  bytes received via SQL*Net from client2  SQL*Net roundtrips to/from client0  sorts (memory)0  sorts (disk)1  rows processed

从上面的测试,很清楚地看出,(owner, object_id)的成本消耗最低。

问题2,既然问题1解决了,上次的结论,还正确?

从测试结论看,上次的结论,是错误的,显然(owner, object_id)复合索引的效率最高,object的单键值索引,条件owner不是索引的组成部分,自然是无法使用该索引,那什么情况下,(object_id, owner)的效率可以?

这种索引的结构,owner重复值很少,

就像这个测试中,owner='USER2'的记录只有几条,重复值很少,这条语句执行,用到的是INDEX FAST FULL SCAN,

SQL> select max(object_id) from t where owner='USER2';Execution Plan
----------------------------------------------------------
Plan hash value: 2276624515----------------------------------------------------------------------------------
| Id  | Operation             | Name     | Rows  | Bytes | Cost (%CPU)| Time     |
----------------------------------------------------------------------------------
|   0 | SELECT STATEMENT      |          |     1 |    30 |    18   (0)| 00:00:01 |
|   1 |  SORT AGGREGATE       |          |     1 |    30 |            |          |
|*  2 |   INDEX FAST FULL SCAN| IDX_T_01 |     1 |    30 |    18   (0)| 00:00:01 |
----------------------------------------------------------------------------------Predicate Information (identified by operation id):
---------------------------------------------------2 - filter("OWNER"='USER2')Note
------ dynamic sampling used for this statement (level=2)Statistics
----------------------------------------------------------0  recursive calls0  db block gets58  consistent gets0  physical reads0  redo size534  bytes sent via SQL*Net to client524  bytes received via SQL*Net from client2  SQL*Net roundtrips to/from client0  sorts (memory)0  sorts (disk)1  rows processed

但是,如果owner重复值很高,如下这种结构,就像这个测试中,owner='SYS',或者一个不存在的值,owner='X',此时几乎就要做一次完整的INDEX FAST FULL SCAN,相比(owner, object_id)的INDEX RANGE SCAN,效率要低些,

因此,在这个测试中,(object_id, owner)效率的高低,取决于owner值的数据分布,而(owner, object_id)效率高低,和数据分布,没任何关系,这个owner=的条件,消耗几个buffer就可以,再通过INDEX RANGE SCAN MIN/MAX,得到他的最值。

对recursive calls以及索引原理的准确理解,是判断这个问题的关键,很明显,上次的测试过程,自己犯了错误,给各位造成困惑,抱歉,多谢各位前辈、朋友的指教。

对recursive calls的深刻理解相关推荐

  1. 通过配置ssh深刻理解puppet的语法及工作机制

    通过配置ssh深刻理解puppet的语法及工作机制 需求分析 1).要求openssh-server处于被安装状态 2).要求在配置文件/etc/ssh/sshd_config正确的情况下,sshd服 ...

  2. F#学习之路(2) 深刻理解函数(上)

    函数在函数式编程语言中是一等公民,是函数式语言中最重要的基本组成元素,也是其名称的由来. F# 中的函数之如C#中的类,是组织程序结构的最基本单元.是命令式编程语言中函数或OO编程语言中方法的超集.超 ...

  3. 曲线均匀分布_曲线篇:深刻理解B 样条曲线(下)

    前两篇中讲解了贝塞尔曲线和B样条基础. FrancisZhao:曲线篇: 贝塞尔曲线​zhuanlan.zhihu.com FrancisZhao:曲线篇:深刻理解B 样条曲线(上)​zhuanlan ...

  4. 【JavaScript】JavaScript模拟实现面向对象一张图帮助你深刻理解原型链和原型对象

    文章目录 一.JavaScript模拟面向对象 1.函数是类 2.函数中各种变量的声明 3.关于函数内的this 小结:JavaScript中函数是什么? 4.练习:面向对象思想编写Complex类 ...

  5. 软件实训之深刻理解原型图设计的核心

    软件实训之深刻理解原型图设计的核心 内容关键词:  原型图设计 知识来源: 网络资源汇总整理.张森鹏讲课视频汇总整理 课程: 软件项目实训   授课老师:张森鹏(新浪ID:sunlifestyle,中 ...

  6. 任正非谈接班人要求:要具有对新技术与客户需求的深刻理解

    日前,华为颁布了2019年048号总裁办电子邮件,该邮件转发了摘自<管理新视野>上的一篇华为创始人.总裁任正非十几年前的谈话,涉及了正职.副职的能力与要求,也提到了干部需要具备的素质.提拔 ...

  7. 【CSDN博客精品文章,佟强】深刻理解Java编程的7个例子

    深刻理解Java编程的7个例子 http://blog.csdn.net/microtong/archive/2009/11/07/4782093.aspx

  8. 《从0到1-全面深刻理解MySQL系列》- 最详细的MySQL安装流程(Window版)

    个人主页: IT学习日记 版权: 本文由[IT学习日记]原创.在CSDN首发 如果文章对你有帮助.欢迎关注.点赞.收藏(一键三连).有任何问题欢迎私信,看到会及时回复! 文章大纲 下载前需要了解的一些 ...

  9. 关于WM_ERASEBKGND和WM_PAINT的深刻理解

    关于WM_ERASEBKGND和WM_PAINT的深刻理解 原创 sdeeds 发布于2011-10-10 15:59:05 阅读数 19643 收藏 更新于2011-10-10 16:10:25 版 ...

最新文章

  1. SpringBoot与SpringMVC的区别是什么?
  2. 《互联网运营智慧》之自序(新)
  3. Redis高级客户端Lettuce详解
  4. 详解/etc/fstab文件内容
  5. linux 系统如何防止攻击
  6. R语言比较运算符和逻辑运算符
  7. php 日期 间隔,PHP实现计算日期间隔天数的方法
  8. 安卓手机可以改鸿蒙吗,华为鸿蒙2.0可以替代安卓吗,华为鸿蒙2.0优势在哪
  9. 【算法分析与设计】基数排序
  10. json和python中字典的区别和联系_Python中 json字符串和字典的区别
  11. Pyqt 打开外部链接的几种方法
  12. Best Coder Lotus and Characters
  13. 抖音短视频内容理解和推荐算法
  14. 狄利克雷过程(Dirichlet Process)
  15. 计算机组成原理中机器码怎么看,《计算机组成原理》汇编指令机器码对应列表...
  16. VMProtect修复导入表的插件
  17. 计算机应用基础演讲怎么开口,计算机应用基础讲课稿
  18. MySQL 管理工具:Navicat for MySQL 8.0.19 中文版(破解版)
  19. Levels - 虚幻引擎场景制作
  20. 完美:利用旧版iCloud更改Apple ID地区

热门文章

  1. 毕业设计 基于stm32的智能婴儿车系统(源码+硬件+论文)
  2. 电脑主板的BIOS参数为何要使用电池来存储?
  3. (3)LOAM的安装运行——地图保存及bug解决
  4. 糟心!准考证上没有考场和座位号咋办?准考证打印了个寂寞?
  5. camunda-external-task-java外部任务项目启动失败,Error creating bean with name ‘externalTaskClient‘: .....
  6. 828. 统计子串中的唯一字符
  7. 【ROS教程 001】ROS机器人系统简介及安装
  8. KinectV2驱动安装(OpenNI问题解决)
  9. 基于单片机的霍尔测速系统
  10. 2s-AGCN Skeleton-Based Action Recognition 代码学习