Oracle热爱者的天地

 

 

昆鹏数据恢复中心——技术引导未来,服务创造价值!!

关于索引的检验  之四

 

上次看了对索引执行大量删除之后,索引检索反而比全面检索慢很多。这次要根据这个奇怪的检验结果,看看 Oracle 对空数据块的访问情况。为了说明这个奇怪结果的原因,请查看下面的 INDEX_STATS 的内容与 TREEDUMP 。

◎TEST01 ( 1 万笔(删除 99 万笔))的 INDEX_STATS 的内容

*************************************************************

SELECT HEIGHT,BLOCKS,LF_ROWS,LF_BLKS,BR_ROWS,BR_BLKS FROM INDEX_STATS ;

 

HEIGHT BLOCKS LF_ROWS LF_BLKS BR_ROWS BR_BLKS

--------- --------- --------- --------- --------- ---------

3 51200 10000 13793 13792 112

*************************************************************

◎TEST01 ( 1 万笔(删除 99 万笔))的 TREEDUMP 的内容(有缩减)

*************************************************************

ALTER SESSION SET EVENTS 'IMMEDIATE TRACE NAME TREEDUMP LEVEL 3539' ;

 

----- begin tree dump

branch: 0x2000003 33554435 (0: nrow: 111, level: 2)

branch: 0x 20000a 3 33554595 (-1: nrow: 120, level: 1)

leaf: 0x2000004 33554436 (-1: nrow: 0)

leaf: 0x2001b 2c 33561388 (0: nrow: 0)

leaf: 0x2000d98 33557912 (1: nrow: 0)

leaf: 0x 2002c 34 33565748 (2: nrow: 0)

leaf: 0x200036b 33555307 (3: nrow: 0)

leaf: 0x2001b2d 33561389 (4: nrow: 0)

leaf: 0x2000d99 33557913 (5: nrow: 0)

:

:

branch: 0x 200145f 33559647 (98: nrow: 107, level: 1)

leaf: 0x2000988 33556872 (-1: nrow: 0)

leaf: 0x 2002a 7a 33565306 (0: nrow: 0)

:

:

leaf: 0x 2002a 81 33565313 (16: nrow: 0)

leaf: 0x200145d 33559645 (17: nrow: 0)

leaf: 0x 2002a 82 33565314 (18: nrow: 0)

leaf: 0x2000d41 33557825 (19: nrow: 0)

leaf: 0x200337b 33567611 (20: nrow: 3)

leaf: 0x 2001a 8f 33561231 (21: nrow: 7)

leaf: 0x 200337c 33567612 (22: nrow: 7)

:

:

leaf: 0x2000d97 33557911 (125: nrow: 7)

leaf: 0x200344d 33567821 (126: nrow: 6)

leaf: 0x2001b2b 33561387 (127: nrow: 7)

leaf: 0x200344e 33567822 (128: nrow: 7)

leaf: 0x2000368 33555304 (129: nrow: 7)

----- end tree dump

*************************************************************

首先请大家注意 LF_BLKS 、 BR_ROWS 和 BR_BLKS 。虽然删除了 99 万笔数据,但这些值还是和有 100 万笔数据的时候一模一样。

◎TEST01 ( 100 万笔)的 INDEX_STATS 的内容

*************************************************************

HEIGHT BLOCKS LF_ROWS LF_BLKS BR_ROWS BR_BLKS

--------- --------- --------- --------- --------- ---------

3 51200 1000000 13793 13792 112

*************************************************************

LF_BLKS 表示实际存在的叶数据块的数量,请大家先留着印象, 13793 这个值和索引的 I/O 次数 13106 很接近。

对 TEST01 ( 1 万笔(删除 99 万笔))的检索结果请看

 

接下来要看 TREEDUMP 。上面显示的 TREEDUMP 是完整输出的一部分,注意到从最前面的叶数据块开始 0 一直持续出现。这个 0 实际上一直持续到第 12413 个数据块,非 0 的叶数据块有 1380 个数据块。换句话说, 12413 + 1380 和 LF_BLKS 的值 13793 一致。

从上面的分析可知索引检验的 I/O 次数为 13106 ,结果如下:

13106 = 根 (1) + 枝 (1) + 5000 笔的叶 (691) + 0 的叶 (12413)
()内的数字代表对索引的 I/O 次数。



这个结果在 “ 索引 ” 主题的第一期曾介绍过,删除之后的空数据块,实际上并没有从索引中清除出去,索引仍然保留。而且我们证明了那些空数据块也会被访问到,这个结果实在令人惊讶。之前说过这是 “ 索引构造的问题 ” ,但是即便是为了保持性能而采用这种构造,这样的构造未免也太粗糙了 ! 例如,应该有不少读者管理数据库的时候会执行 “ 年度改变的时候要把前年的数据删除 ” 这样的操作,如果执行这种系统维护的 DBA 不知道索引构造上的问题,删除后没有执行 REBUILD 之类的维护动作的话,那些为了提高性能而建立的索引就反倒会使性能下降。

下次要看看索引的构造和 SQL optimizer 之间的关系。

上次介绍了大量的删除处理会导致索引出现很多空数据块,而且这些空数据块都会被访问( access )到,同时我们分析了发生这种现象的原因。这次我们要看看索引结构和 SQL 优化器 (Optimizer) 之间的关系。

◎ SQL 优化器
执行的 SQL 语句会在翻译过程中创建执行计划。 Oracle 的 SQL 执行引擎具备这种功能的部件称为优化器。创建执行计划的方法有两种,分别是 “ 基于规则 ” 「 rule base 」和 “ 基于成本 ” 「 cost base 」,两种机能分别称为基于规则的优化器「 rule base optimizer ( RBO )」和基于成本的优化器「 cost base optimizer ( CBO )」。先向大家介绍这两种功能和索引的关系。
RBO = 条件式允许使用索引的话一定会执行索引检索
CBO = 即使条件式允许使用索引也会参照 ANALYZE 信息根据情况执行,因此有可能不执行索引检索

如果对表执行 ANALYZE 就是 CBO ,如果没有执行 ANALYZE 就是 RBO 。 CBO 的「 cost 」是对 Oracle 数据块的 I/O 次数,实际上是以这个 I/O 次数为基准,比较索引检索的 cost 和全表扫描( Full )的 cost ,选择 I/O 次数比较少的那一种。

针对表 TEST01 ( 1 万笔(删除 99 万笔))执行 ANALYZE 之前和 ANALYZE 之后分别执行同样的 SELECT 语句,结果如下面的网页所示。
ANALYZE 之前

ANALYZE 之后

只要看看 ANALYZE 之后的检索结果的【检索 1 】应该就能了解,虽然条件式可以使用索引,但是对索引的 I/O 次数是 0 。这说明 CBO 是根据 ANALYZE 的讯息来判断检索的方式,分析显示检索 1 万笔之中的 5000 笔( 50% ),全表扫描会比索引检索的 cost 低。换句话说,数据库的判断是,与其一一访问存放于索引键的叶数据块,不如利用 Oracle 的初始设定参数「 db_file_multiblock_read_count 」,以几个数据块为单位 ( 预设是 8 个 ) 直接访问实际存放数据的 Oracle 数据块。

上面的结果是对 1 万笔的表 50% 的数据( 5000 笔数据)执行检索,那么如果我们把检索的范围缩得很小很小,比如说使用范围条件式,执行只返回一笔数据的 SELECT 语句,会发生什么情况?
检索结果:

在上面的条件式使用索引的检索结果,会发生对索引的 I/O ,这是理所当然的结果。前一次检索是全体的 50% ,所以 CBO 判断全表扫描的成本比索引检索低。这次的检索不到全体的 0.01% , 所以 CBO 判断索引检索的成本更低。

不过,大家是否注意到这次空的叶数据块也发生 I/O 呢?键在叶数据块里一定会由小到大存放,如果只读最前面的叶数据块的最前面的键,应该只有根( 1 )、枝( 1 )、叶( 1 )这 3 次 I/O ,结果竟然还是和 ANALYZE 之前一样对空的叶数据块发生了 12413 次 I/O 。
Access 空的叶数据库的情况

从这些结果可知, CBO 会根据 ANALYZE 的讯息,按照 CBO 本身的标准﹝要读取哪个数据块﹞判断要不要对照索引。可是因为判断的时候没有考虑到索引的构造,所以导致出现偏差﹝ Skew ﹞,或是在遇到密度低的索引时未必能得到最好的结果。以后我们会找机会深入检验这个 CBO 判断标准,并向大家说明。各位读者有时间的话不妨自己试着检验看看。

我们都是热爱 Oracle 技术的研发人员,希望能让更多人认识 Oracle 。这份电子杂志不刊登外界广告,但是读者的数量是我们判断电子杂志存在价值的依据。如果您也认同电子杂志的内容,请介绍给您的朋友。感谢大家的支持 !

关于问题专区

我们很乐意回答大家的问题,如果您对于 Oracle 性能有任何疑问,只要我们能给出对您有价值的情报,一定会与您分享。欢迎大家尽量发问,我们会在今后的内容中回答您的问题!请您把问题发送到 这里 。QQ:9417901

昆鹏数据恢复中心介绍

昆鹏数据恢复中心于 2004 年创立于沈阳浑河北岸的三好街高新技术产业区里,业务遍布中国。集项目研究、应用、实施、销售、服务于一体,为客户提供管理咨询、大型应用系统的性能优化、软件研发等一体化技术服务。昆鹏数据恢复中心由资深软件行业专家、优秀的技术开发队伍和具备先进理念的管理团队形成核心力量,具有丰富的项目管理经验和雄厚的技术实力。

 

昆鹏数据恢复中心服务内容                                         

磁盘阵列数据恢复

Oracle数据库恢复