0

0

dump浅析B树索引

php中文网

php中文网

发布时间:2016-06-07 16:13:16

|

1419人浏览过

|

来源于php中文网

原创

oracle中默认的索引类型是B树索引。还有位图索引,反向键索引,hash索引,基于函数的索引。 本篇主要介绍B树索引,通过转储分析。对于索引的扫描类型,索引的基本操作不做详细的介绍。 系统信息: [oracle@localhost ~]$ cat /etc/issue Enterprise Linux Ent

oracle中默认的索引类型是B树索引。还有位图索引,反向键索引,hash索引,基于函数的索引。
本篇主要介绍B树索引,通过转储分析。对于索引的扫描类型,索引的基本操作不做详细的介绍。
系统信息:
[oracle@localhost ~]$ cat /etc/issue
Enterprise Linux Enterprise Linux Server release 5.5 (Carthage)
Kernel \r on an \m

数据库版本:
SQL> select * from v$version where rownum =1 ;

BANNER
--------------------------------------------------------------------------------
Oracle Database 11g Enterprise Edition Release 11.2.0.1.0 - Production

SQL> show user;
USER 为 "HR"
SQL> desc tt;
名称 是否为空? 类型
----------------------------------------- -------- ----------------------------
ID NUMBER
NAME VARCHAR2(10)
SQL> select count(rownum) from tt;
COUNT(ROWNUM)
-------------
3670016
基于ID创建索引index_t

SQL> create index index_t on tt(id) tablespace users;

索引已创建。

SQL> select object_id from dba_objects where object_name=
2 'INDEX_T';
数据库中segment有数据段,索引段,undo段,它们和表名,索引名不是同一概念,但是名字是相同的。

OBJECT_ID
----------
76332
转储索引:
SQL> alter session set events 'immediate trace name treedump level 76332';
会话已更改。

----- begin tree dump
branch: 0x10038ab 16791723 (0: nrow: 15, level: 2)
branch: 0x100540b 16798731 (-1: nrow: 503, level: 1)
leaf: 0x10038ac 16791724 (-1: nrow: 512 rrow: 512)
leaf: 0x10038ad 16791725 (0: nrow: 512 rrow: 512)
leaf: 0x10038ae 16791726 (1: nrow: 512 rrow: 512)
leaf: 0x10038af 16791727 (2: nrow: 512 rrow: 512)
leaf: 0x10038b0 16791728 (3: nrow: 512 rrow: 512)
leaf: 0x10038b1 16791729 (4: nrow: 512 rrow: 512)
leaf: 0x10038b2 16791730 (5: nrow: 512 rrow: 512)
leaf: 0x10038b3 16791731 (6: nrow: 512 rrow: 512)
leaf: 0x10038b4 16791732 (7: nrow: 512 rrow: 512)
leaf: 0x10038b5 16791733 (8: nrow: 512 rrow: 512)
leaf: 0x10038b6 16791734 (9: nrow: 512 rrow: 512)
leaf: 0x10038b7 16791735 (10: nrow: 512 rrow: 512)
leaf: 0x10038b9 16791737 (11: nrow: 512 rrow: 512)
leaf: 0x10038ba 16791738 (12: nrow: 512 rrow: 512)
leaf: 0x10038bb 16791739 (13: nrow: 512 rrow: 512)
leaf: 0x10038bc 16791740 (14: nrow: 512 rrow: 512)
leaf: 0x10038bd 16791741 (15: nrow: 512 rrow: 512)
leaf: 0x10038be 16791742 (16: nrow: 512 rrow: 512)
leaf: 0x10038bf 16791743 (17: nrow: 512 rrow: 512)
leaf: 0x10038c0 16791744 (18: nrow: 512 rrow: 512)
leaf: 0x10038c1 16791745 (19: nrow: 512 rrow: 512)
leaf: 0x10038c2 16791746 (20: nrow: 512 rrow: 512)
leaf: 0x10038c3 16791747 (21: nrow: 512 rrow: 512)
leaf: 0x10038c4 16791748 (22: nrow: 512 rrow: 512)
leaf: 0x10038c5 16791749 (23: nrow: 512 rrow: 512)
leaf: 0x10038c6 16791750 (24: nrow: 512 rrow: 512)
leaf: 0x10038c7 16791751 (25: nrow: 512 rrow: 512)
leaf: 0x10038c9 16791753 (26: nrow: 512 rrow: 512)
leaf: 0x10038ca 16791754 (27: nrow: 512 rrow: 512)
leaf: 0x10038cb 16791755 (28: nrow: 512 rrow: 512)
leaf: 0x10038cc 16791756 (29: nrow: 512 rrow: 512)
leaf: 0x10038cd 16791757 (30: nrow: 512 rrow: 512)
leaf: 0x10038ce 16791758 (31: nrow: 512 rrow: 512)
leaf: 0x10038cf 16791759 (32: nrow: 512 rrow: 512)
leaf: 0x10038d0 16791760 (33: nrow: 512 rrow: 512)
leaf: 0x10038d1 16791761 (34: nrow: 512 rrow: 512)
leaf: 0x10038d2 16791762 (35: nrow: 512 rrow: 512)
leaf: 0x10038d3 16791763 (36: nrow: 512 rrow: 512)
leaf: 0x10038d4 16791764 (37: nrow: 512 rrow: 512)
leaf: 0x10038d5 16791765 (38: nrow: 512 rrow: 512)
leaf: 0x10038d6 16791766 (39: nrow: 512 rrow: 512)
leaf: 0x10038d7 16791767 (40: nrow: 512 rrow: 512)
leaf: 0x10038d9 16791769 (41: nrow: 512 rrow: 512)
leaf: 0x10038da 16791【本文来自鸿网互联 (http://www.68idc.cn)】770 (42: nrow: 512 rrow: 512)
leaf: 0x10038db 16791771 (43: nrow: 512 rrow: 512)
leaf: 0x10038dc 16791772 (44: nrow: 512 rrow: 512)
leaf: 0x10038dd 16791773 (45: nrow: 512 rrow: 512)
leaf: 0x10038de 16791774 (46: nrow: 512 rrow: 512)
...........................................................................
....
....
....
----- end tree dump

这是一棵平衡树,因为平衡树的查找效率很高,根节点到所有的叶子节点的高度相同。 branch表示的是根节点。以上选取了一部分,已经按从左向右拍好序了。
leaf: 0x10038ac 16791724 (-1: nrow: 512 rrow: 512) 我们选取这一列:

把十六进制,和十进制数相互转换:
SQL> select to_number('10038ac','xxxxxxxxxxxxxxxx') from dual;

TO_NUMBER('10038AC','XXXXXXXXXXXXXXXX')
---------------------------------------
16791724

SQL> select to_char('16791724','xxxxxxxxxxxxxxxx') from dual;


TO_CHAR('16791724','XXXXXXXXXXXXXX
----------------------------------
10038ac


我们利用oracle中提供的一个包可以求得索引所在的文件号,块号:
SQL> select dbms_utility.data_block_address_file(16791724) from dual;


DBMS_UTILITY.DATA_BLOCK_ADDRESS_FILE(16791724)
----------------------------------------------
4

SQL> select dbms_utility.data_block_address_block(16791724) from dual;


DBMS_UTILITY.DATA_BLOCK_ADDRESS_BLOCK(16791724)
-----------------------------------------------

14508



通过查视图dba_extends,索引存储在数据文件4,块14508在起始块范围内。
\
此时我们dump数据文件4,块14508:

SQL> alter system dump datafile 4 block 14508;


系统已更改。
row#0[8020] flag: ------, lock: 0, len=12
col 0; len 2; (2): c1 02
col 1; len 6; (6): 01 00 1b ab 00 01
row#1[8008] flag: ------, lock: 0, len=12
col 0; len 2; (2): c1 02
col 1; len 6; (6): 01 00 1b ab 00 03
row#2[7996] flag: ------, lock: 0, len=12
col 0; len 2; (2): c1 02
col 1; len 6; (6): 01 00 1b ab 00 08
row#3[7984] flag: ------, lock: 0, len=12
col 0; len 2; (2): c1 02
col 1; len 6; (6): 01 00 1b ab 00 0a
row#4[7972] flag: ------, lock: 0, len=12
col 0; len 2; (2): c1 02
col 1; len 6; (6): 01 00 1b ab 00 0f
row#5[7960] flag: ------, lock: 0, len=12
col 0; len 2; (2): c1 02
col 1; len 6; (6): 01 00 1b ab 00 11
row#6[7948] flag: ------, lock: 0, len=12
col 0; len 2; (2): c1 02
col 1; len 6; (6): 01 00 1b ab 00 16
row#7[7936] flag: ------, lock: 0, len=12
col 0; len 2; (2): c1 02
col 1; len 6; (6): 01 00 1b ab 00 18
row#8[7924] flag: ------, lock: 0, len=12
col 0; len 2; (2): c1 02
col 1; len 6; (6): 01 00 1b ab 00 1d
row#9[7912] flag: ------, lock: 0, len=12
col 0; len 2; (2): c1 02
col 1; len 6; (6): 01 00 1b ab 00 1f
row#10[7900] flag: ------, lock: 0, len=12
col 0; len 2; (2): c1 02
col 1; len 6; (6): 01 00 1b ab 00 24
row#11[7888] flag: ------, lock: 0, len=12
col 0; len 2; (2): c1 02
col 1; len 6; (6): 01 00 1b ab 00 26
row#12[7876] flag: ------, lock: 0, len=12
col 0; len 2; (2): c1 02
col 1; len 6; (6): 01 00 1b ab 00 2b
row#13[7864] flag: ------, lock: 0, len=12
col 0; len 2; (2): c1 02
col 1; len 6; (6): 01 00 1b ab 00 2d
row#14[7852] flag: ------, lock: 0, len=12
col 0; len 2; (2): c1 02
col 1; len 6; (6): 01 00 1b ab 00 32
row#15[7840] flag: ------, lock: 0, len=12
col 0; len 2; (2): c1 02
col 1; len 6; (6): 01 00 1b ab 00 34
row#16[7828] flag: ------, lock: 0, len=12
col 0; len 2; (2): c1 02
col 1; len 6; (6): 01 00 1b ab 00 39
row#17[7816] flag: ------, lock: 0, len=12
col 0; len 2; (2): c1 02
col 1; len 6; (6): 01 00 1b ab 00 3b
row#18[7804] flag: ------, lock: 0, len=12
col 0; len 2; (2): c1 02
col 1; len 6; (6): 01 00 1b ab 00 40
row#19[7792] flag: ------, lock: 0, len=12
col 0; len 2; (2): c1 02
col 1; len 6; (6): 01 00 1b ab 00 42
row#20[7780] flag: ------, lock: 0, len=12
...............................................................

.......
选取这一行为例:
row#0[8020] flag: ------, lock: 0, len=12
col 0; len 2; (2): c1 02
col 1; len 6; (6): 01 00 1b ab 00 01
col 0 表示第一列,长度为2,c1 02表示是多少呢?

SQL> select * from tt where rownum<4 order by id;


ID NAME
---------- --------------------
1 wO
2 wang
6 hong

SQL> select dump(1,16) from dual;


DUMP(1,16)
----------------------------------

Typ=2 Len=2: c1,2 ==>这里是c1 02,0省略了

这下清楚了吧,第一行第一列存储的是1,orale存储数据的方法很复杂。

col 1表示的是第二列,长度是6, 01 00 1b ab 00 01就是索引的值,是十六进制数,我们可以转化为二进制数:
00000001 00000000 00011011 10101011 00000000 00000001
-----------------------------------------------------------------------------------------------------------------------------------------------------------
00000001 00 ==>1x2x2=4 前10位表示了数据文件号
000000 00011011 10101011 ==>4096+2048+512+256+128+32+8+2+1=7083 这里的22位表示了块号
00000000 00000001==>1 16位代表着行号
此时排序并查rowid:
\
此时用第一列的rowid,
通过oracle提供的一个包,可以求出对象编号,文件号,块号:
执行如下图:
\
上面从索引存储的段以及数据段进行分析。
我们知道索引不一定会提高查询效率,往往乱建索引会严重影响查询效率,系统用不用索引,我们不能干预(但是dba可以手动改变),是oracle CBO选择的结果。
下面我们可以做一个小实验:
SQL> select count(rowid) from t;


COUNT(ROWID)
------------
4718644


SQL> select count(rowid) from t where id=1;


COUNT(ROWID)
------------
4718592


SQL> select count(rowid) from t where id=2;


COUNT(ROWID)
------------
26


SQL> select count(rowid) from t where id=3;


COUNT(ROWID)
------------
26


SQL> set autotrace traceonly;
SQL> select * from tt;



执行计划
----------------------------------------------------------
Plan hash value: 264906180


--------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 3556K| 67M| 1742 (2)| 00:00:21 |
| 1 | TABLE ACCESS FULL| TT | 3556K| 67M| 1742 (2)| 00:00:21 |
--------------------------------------------------------------------------


Note
-----
- dynamic sampling used for this statement (level=2)


此时是全表扫描读取,是多块读取,,这样读取比较快,如果此时用索引,则效率会低。
SQL> select * from tt where id=5;


执行计划
----------------------------------------------------------
Plan hash value: 3103123359


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


-------


| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Tim


e |


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


-------


| 0 | SELECT STATEMENT | | 5 | 100 | 4 (0)| 00:


00:01 |


| 1 | TABLE ACCESS BY INDEX ROWID| TT | 5 | 100 | 4 (0)| 00:


00:01 |


|* 2 | INDEX RANGE SCAN | INDEX_T | 5 | | 3 (0)| 00:


00:01 |


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


-------




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


2 - access("ID"=5)


Note
-----
- dynamic sampling used for this statement (level=2)



此时是索引读取。
SQL> select * from tt where id=1;


执行计划
----------------------------------------------------------
Plan hash value: 264906180


--------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 2121K| 40M| 3644 (2)| 00:00:44 |
|* 1 | TABLE ACCESS FULL| TT | 2121K| 40M| 3644 (2)| 00:00:44 |
--------------------------------------------------------------------------


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


1 - filter("ID"=1)


Note
-----
- dynamic sampling used for this statement (level=2)


看到了吧,此时是全表扫描读取,数据库是很聪明的吧!


热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

WorkBuddy
WorkBuddy

腾讯云推出的AI原生桌面智能体工作台

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
TypeScript类型系统进阶与大型前端项目实践
TypeScript类型系统进阶与大型前端项目实践

本专题围绕 TypeScript 在大型前端项目中的应用展开,深入讲解类型系统设计与工程化开发方法。内容包括泛型与高级类型、类型推断机制、声明文件编写、模块化结构设计以及代码规范管理。通过真实项目案例分析,帮助开发者构建类型安全、结构清晰、易维护的前端工程体系,提高团队协作效率与代码质量。

26

2026.03.13

Python异步编程与Asyncio高并发应用实践
Python异步编程与Asyncio高并发应用实践

本专题围绕 Python 异步编程模型展开,深入讲解 Asyncio 框架的核心原理与应用实践。内容包括事件循环机制、协程任务调度、异步 IO 处理以及并发任务管理策略。通过构建高并发网络请求与异步数据处理案例,帮助开发者掌握 Python 在高并发场景中的高效开发方法,并提升系统资源利用率与整体运行性能。

46

2026.03.12

C# ASP.NET Core微服务架构与API网关实践
C# ASP.NET Core微服务架构与API网关实践

本专题围绕 C# 在现代后端架构中的微服务实践展开,系统讲解基于 ASP.NET Core 构建可扩展服务体系的核心方法。内容涵盖服务拆分策略、RESTful API 设计、服务间通信、API 网关统一入口管理以及服务治理机制。通过真实项目案例,帮助开发者掌握构建高可用微服务系统的关键技术,提高系统的可扩展性与维护效率。

178

2026.03.11

Go高并发任务调度与Goroutine池化实践
Go高并发任务调度与Goroutine池化实践

本专题围绕 Go 语言在高并发任务处理场景中的实践展开,系统讲解 Goroutine 调度模型、Channel 通信机制以及并发控制策略。内容包括任务队列设计、Goroutine 池化管理、资源限制控制以及并发任务的性能优化方法。通过实际案例演示,帮助开发者构建稳定高效的 Go 并发任务处理系统,提高系统在高负载环境下的处理能力与稳定性。

51

2026.03.10

Kotlin Android模块化架构与组件化开发实践
Kotlin Android模块化架构与组件化开发实践

本专题围绕 Kotlin 在 Android 应用开发中的架构实践展开,重点讲解模块化设计与组件化开发的实现思路。内容包括项目模块拆分策略、公共组件封装、依赖管理优化、路由通信机制以及大型项目的工程化管理方法。通过真实项目案例分析,帮助开发者构建结构清晰、易扩展且维护成本低的 Android 应用架构体系,提升团队协作效率与项目迭代速度。

92

2026.03.09

JavaScript浏览器渲染机制与前端性能优化实践
JavaScript浏览器渲染机制与前端性能优化实践

本专题围绕 JavaScript 在浏览器中的执行与渲染机制展开,系统讲解 DOM 构建、CSSOM 解析、重排与重绘原理,以及关键渲染路径优化方法。内容涵盖事件循环机制、异步任务调度、资源加载优化、代码拆分与懒加载等性能优化策略。通过真实前端项目案例,帮助开发者理解浏览器底层工作原理,并掌握提升网页加载速度与交互体验的实用技巧。

102

2026.03.06

Rust内存安全机制与所有权模型深度实践
Rust内存安全机制与所有权模型深度实践

本专题围绕 Rust 语言核心特性展开,深入讲解所有权机制、借用规则、生命周期管理以及智能指针等关键概念。通过系统级开发案例,分析内存安全保障原理与零成本抽象优势,并结合并发场景讲解 Send 与 Sync 特性实现机制。帮助开发者真正理解 Rust 的设计哲学,掌握在高性能与安全性并重场景中的工程实践能力。

227

2026.03.05

PHP高性能API设计与Laravel服务架构实践
PHP高性能API设计与Laravel服务架构实践

本专题围绕 PHP 在现代 Web 后端开发中的高性能实践展开,重点讲解基于 Laravel 框架构建可扩展 API 服务的核心方法。内容涵盖路由与中间件机制、服务容器与依赖注入、接口版本管理、缓存策略设计以及队列异步处理方案。同时结合高并发场景,深入分析性能瓶颈定位与优化思路,帮助开发者构建稳定、高效、易维护的 PHP 后端服务体系。

532

2026.03.04

AI安装教程大全
AI安装教程大全

2026最全AI工具安装教程专题:包含各版本AI绘图、AI视频、智能办公软件的本地化部署手册。全篇零基础友好,附带最新模型下载地址、一键安装脚本及常见报错修复方案。每日更新,收藏这一篇就够了,让AI安装不再报错!

171

2026.03.04

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
【李炎恢】ThinkPHP8.x 后端框架课程
【李炎恢】ThinkPHP8.x 后端框架课程

共50课时 | 4.7万人学习

SQL优化与排查(MySQL版)
SQL优化与排查(MySQL版)

共26课时 | 2.4万人学习

MySQL索引优化解决方案
MySQL索引优化解决方案

共23课时 | 2.1万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号