dump浅析B树索引
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工具

Undresser.AI Undress
人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover
用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool
免费脱衣服图片

Clothoff.io
AI脱衣机

AI Hentai Generator
免费生成ai无尽的。

热门文章

热工具

记事本++7.3.1
好用且免费的代码编辑器

SublimeText3汉化版
中文版,非常好用

禅工作室 13.0.1
功能强大的PHP集成开发环境

Dreamweaver CS6
视觉化网页开发工具

SublimeText3 Mac版
神级代码编辑软件(SublimeText3)

热门话题

数据导入方法:1. 使用 SQLLoader 实用程序:准备数据文件、创建控制文件、运行 SQLLoader;2. 使用 IMP/EXP 工具:导出数据、导入数据。提示:1. 大数据集推荐 SQL*Loader;2. 目标表应存在,列定义匹配;3. 导入后需验证数据完整性。

要查询 Oracle 表空间大小,请遵循以下步骤:确定表空间名称,方法是运行查询:SELECT tablespace_name FROM dba_tablespaces;查询表空间大小,方法是运行查询:SELECT sum(bytes) AS total_size, sum(bytes_free) AS available_space, sum(bytes) - sum(bytes_free) AS used_space FROM dba_data_files WHERE tablespace_

创建 Oracle 表涉及以下步骤:使用 CREATE TABLE 语法指定表名、列名、数据类型、约束和默认值。表名应简洁、描述性,且不超过 30 个字符。列名应描述性,数据类型指定列中存储的数据类型。NOT NULL 约束确保列中不允许使用空值,DEFAULT 子句可指定列的默认值。PRIMARY KEY 约束标识表的唯一记录。FOREIGN KEY 约束指定表中的列引用另一个表中的主键。请参见示例表 students 的创建,其中包含主键、唯一约束和默认值。

使用 ALTER TABLE 语句,具体语法如下:ALTER TABLE table_name ADD column_name data_type [constraint-clause]。其中:table_name 为表名,column_name 为字段名,data_type 为数据类型,constraint-clause 为可选的约束。示例:ALTER TABLE employees ADD email VARCHAR2(100) 为 employees 表添加 email 字段。

Oracle 打不开的解决办法包括:1. 启动数据库服务;2. 启动监听器;3. 检查端口冲突;4. 正确设置环境变量;5. 确保防火墙或防病毒软件未阻止连接;6. 检查服务器是否已关闭;7. 使用 RMAN 恢复损坏的文件;8. 检查 TNS 服务名称是否正确;9. 检查网络连接;10. 重新安装 Oracle 软件。

Oracle 乱码问题可以通过以下步骤解决:检查数据库字符集以确保与数据相匹配。设置客户端字符集以与数据库相匹配。转换数据或修改列字符集以匹配数据库字符集。使用 Unicode 字符集,并避免多字节字符集。检查数据库和客户端的语言设置是否正确。

Oracle 提供多种去重查询方法:DISTINCT 关键字返回每列的唯一值。GROUP BY 子句对结果分组并返回每个分组的非重复值。UNIQUE 关键字用于创建仅包含唯一行的索引,查询该索引将自动去重。ROW_NUMBER() 函数分配唯一数字并过滤出仅包含第 1 行的结果。MIN() 或 MAX() 函数可返回数字列的非重复值。INTERSECT 运算符返回两个结果集的公共值(无重复项)。

在 Oracle 中创建用户需遵循以下步骤:使用 CREATE USER 语句创建新用户。使用 GRANT 语句授予必要权限。可选:使用 RESOURCE 语句设置配额。配置其他选项,如默认角色和临时表空间。
