Oracle-索引分裂研究
点击上方"蓝字"
关注我们,享更多干货!
索引分裂(Index Block Split),就是索引块的分裂。当一次DML操作修改了索引块上的数据,但是旧有的索引块没有足够的空间去容纳新修改的数据时,将分裂出一个新的索引块,旧有块的部分数据放到新开辟的索引块上去,这个过程就称为索引块的分裂,简称索引分裂。
在分裂的过程中,前台进程需要等待分裂完成之后才能继续操作。如果此时其它会话也要修改这个索引块的数据,那么将会出现索引块的竞争,等待以“enq: TX – index contention”的形式体现,该事件是一个与索引分裂直接相关的等待事件。一般索引块的分裂持有资源和释放非常迅速,并不会对数据库造成严重的性能影响,但是在表操作并发量很大的情况下可能导致严重的竞争。当索引分裂发生时,负责实施分裂的进程会持有相关的队列锁,直到该进程完成分裂操作才会释放该队列锁。在这个过程中负责分裂的进程需要找到合适的新块并将对应的数据移动到该新块中。若在此分裂的过程中,有其它进程INSERT数据到该索引块中,则将进入enq: TX – index contention等待,直到分裂结束锁被释放。
分类
索引分裂有如下几种情况:
(1)按照分裂对象分:
叶子节点分裂:**叶子节点上没有足够的空间容纳新插入的数据。叶子节点分裂的情况最频繁发生,对性能影响最直接。
枝节点分裂:**其下层的节点分裂,会导致在该节点上增加一条记录指向新加的节点,当该节点空间不足时,会发生分裂。
根节点分裂:**特殊的枝节点分裂,分裂需要两个新的数据块,将原有数据转移至两个新节点,原有节点上生成两条记录分别指向新增的数据块。
(2)按照分裂数据块比例分:
9-1分裂:**当事务向索引的最右侧的叶节点上插入一条大于或等于现有索引块上最大值的数据,且该索引块上不存在其它未提交的事务,如果没有足够的空间,那么就会发生9-1分裂。绝大部分数据还保留在旧有节点上,仅有非常少的一部分数据迁移到新节点上。
5-5分裂:**当发生5-5分裂时,有一半索引记录仍存在当前块,而另一半数据移动到新的节点中,旧节点和新节点上的数据比例几乎是持平的。5-5分裂发生的条件:
当左侧节点发生新值插入时(插入到叶子节点中的索引键值小于该块中的最大值)。
当发生DML操作时,索引块上没有足够空间分配新的ITL槽。
当新插入数据大于或等于索引中最大值时,但是数据块上还存在其它未提交的事务。
对性能来说,无论是9-1分裂,还是5-5分裂,都会影响系统的性能。
通过10224事件可以生成索引块分裂及删除了的。
索引分裂实验
基础环境准备
--创建用户表空间
create tablespace zsdba_data datafile '+DATA' size 200M;
create user autoidx identified by autoidx default tablespace zsdba_data;
grant dba to autoidx;--创建表
create table zsdba_idx(id number(20) not null,name varchar(20));
alter table zsdba_idx add constraint pri_id primary key (id);
基础信息统计–之前
--基础信息统计
col owner for a15
col segment_name for a15
col segment_type for a15
set linesize 200
set pagesize 999
select t.owner,t.segment_name,t.segment_type,t.header_file,t.header_block from dba_segments t where t.segment_name in ('ZSDBA_IDX','PRI_ID');
OWNER SEGMENT_NAME SEGMENT_TYPE HEADER_FILE HEADER_BLOCK
--------------- --------------- --------------- ----------- ------------
AUTOIDX PRI_ID INDEX 2 138
AUTOIDX ZSDBA_IDX TABLE 2 130select t.owner,t.segment_name,t.segment_type,t.file_id,t.block_id,t.blocks from dba_extents t where t.segment_name in ('ZSDBA_IDX','PRI_ID');
OWNER SEGMENT_NAME SEGMENT_TYPE FILE_ID BLOCK_ID BLOCKS
--------------- --------------- --------------- ---------- ---------- ----------
AUTOIDX PRI_ID INDEX 2 136 8
AUTOIDX ZSDBA_IDX TABLE 2 128 8col name for a25
select t.inst_id,t.name,t.value from gv$sysstat t where t.NAME like '%splits%' order by t.inst_id,t.name;INST_ID NAME VALUE
---------- ------------------------- ----------1 branch node splits 341 leaf node 90-10 splits 22081 leaf node splits 125251 queue splits 01 root node splits 62 branch node splits 322 leaf node 90-10 splits 8872 leaf node splits 72732 queue splits 02 root node splits 8
数据插入
通过10224事件可以生成索引块分裂及删除的trace
alter session set events '10224 TRACE NAME CONTEXT FOREVER,LEVEL 10';
alter session set tracefile_identifier="STACK_10224";
insert into zsdba_idx select level,'11' from dual connect by level<50000;
commit;
alter session set events '10224 TRACE NAME CONTEXT OFF';
基础信息统计–之后
col owner for a15
col segment_name for a15
col segment_type for a15
set linesize 200
set pagesize 999
select t.owner,t.segment_name,t.segment_type,t.header_file,t.header_block,t.blocks,t.bytes
from dba_segments t where t.segment_name in ('T_IBS_LHR','PRI_ID');OWNER SEGMENT_NAME SEGMENT_TYPE HEADER_FILE HEADER_BLOCK BLOCKS BYTES
--------------- --------------- --------------- ----------- ------------ ---------- ----------
AUTOIDX PRI_ID INDEX 2 138 112 917504select t.owner,t.segment_name,t.segment_type,t.file_id,t.block_id,t.blocks from dba_extents t where t.segment_name in ('ZSDBA_IDX','PRI_ID');
OWNER SEGMENT_NAME SEGMENT_TYPE FILE_ID BLOCK_ID BLOCKS
--------------- --------------- --------------- ---------- ---------- ----------
AUTOIDX PRI_ID INDEX 2 136 8
AUTOIDX PRI_ID INDEX 2 144 8
AUTOIDX PRI_ID INDEX 2 160 8
AUTOIDX PRI_ID INDEX 2 176 8
AUTOIDX PRI_ID INDEX 2 192 8
AUTOIDX PRI_ID INDEX 2 200 8
AUTOIDX PRI_ID INDEX 2 216 8
AUTOIDX PRI_ID INDEX 2 232 8
AUTOIDX PRI_ID INDEX 2 248 8
AUTOIDX PRI_ID INDEX 2 264 8
AUTOIDX PRI_ID INDEX 2 280 8
AUTOIDX PRI_ID INDEX 2 296 8
AUTOIDX PRI_ID INDEX 2 312 8
AUTOIDX PRI_ID INDEX 2 328 8
AUTOIDX ZSDBA_IDX TABLE 2 128 8
AUTOIDX ZSDBA_IDX TABLE 2 152 8
AUTOIDX ZSDBA_IDX TABLE 2 168 8
AUTOIDX ZSDBA_IDX TABLE 2 184 8
AUTOIDX ZSDBA_IDX TABLE 2 208 8
AUTOIDX ZSDBA_IDX TABLE 2 224 8
AUTOIDX ZSDBA_IDX TABLE 2 240 8
AUTOIDX ZSDBA_IDX TABLE 2 256 8
AUTOIDX ZSDBA_IDX TABLE 2 272 8
AUTOIDX ZSDBA_IDX TABLE 2 288 8
AUTOIDX ZSDBA_IDX TABLE 2 304 8
AUTOIDX ZSDBA_IDX TABLE 2 320 8
AUTOIDX ZSDBA_IDX TABLE 2 336 827 rows selected.col name for a25
select t.inst_id,t.name,t.value from gv$sysstat t where t.NAME like '%splits%' order by t.inst_id,t.name;INST_ID NAME VALUE
---------- ------------------------- ----------1 branch node splits 341 leaf node 90-10 splits 23001 leaf node splits 127131 queue splits 01 root node splits 62 branch node splits 322 leaf node 90-10 splits 8872 leaf node splits 73512 queue splits 02 root node splits 8
Trace 数据统计
col value for a80
select value from v$diag_info where name = 'Default Trace File';
VALUE
--------------------------------------------------------------------------------
/u01/app/oracle/diag/rdbms/orcl/orcl1/trace/orcl1_ora_48064_STACK_10224.trc[oracle@19db1:/home/oracle]$ grep 'splitting' orcl1_ora_48064_STACK_10224.trc
splitting leaf,dba 0x0080008b,time 16:59:43.374
splitting leaf,dba 0x0080008c,time 16:59:43.381
.....
[oracle@19db1:/home/oracle]$ grep 'splitting' orcl1_ora_48064_STACK_10224.trc|awk -F '[ |,]' '{print $4}'
0x0080008b
............
0x0080014f
[oracle@19db1:/u01/app/oracle/diag/rdbms/orcl/orcl1/trace]$ grep 'splitting' orcl1_ora_48064_STACK_10224.trc|awk -F '[ |,]' '{print $4}'|uniq|wc -l
92 <=========索引分裂次数
数据分析
索引PRI_ID之dba_extents视图
从索引pri_id的现有块数看,由1个extent扩展至14个extent,目前1个extent有8个block,索引pri_id有112个块,和dba_segments视图统计一致。
数据为有序插入,会产生类型为leaf node 90-10 splits的分裂,即分裂块次数最多有111次。
索引PRI_ID之gv$sysstat视图
从视图gv$sysstat的leaf node 90-10 splits统计值看,插入前后差值为92,小于111次,且等于trace文件中统计到的92次。
INST_ID NAME 插入前 插入后 差集
---------- ------------------------- ---------- ---------- ----------1 branch node splits 34 34 01 leaf node 90-10 splits 2208 2300 92 <======索引分裂1 leaf node splits 12525 12713 1881 queue splits 0 0 01 root node splits 6 6 02 branch node splits 32 32 02 leaf node 90-10 splits 887 887 02 leaf node splits 7273 7351 782 queue splits 0 02 root node splits 8 8
索引分裂衍生-enq:TX-index contention
enq:TX-index contention是一个很常见的等待事件,其专指由于索引分裂产生的竞争等待。最常见的索引竞争一般发生在主键索引上,主键值从序列(sequence)中获取,每个事务都会生成一条新的记录,每条记录都要获得一个新的序列号,因为从sequence中取出的值是单向递增的,当索引中插入数据,并且维护索引结构的时候,不得不一直走向索引的最右侧分支,对于每一个操作,都会想要维护索引中最右边的叶节点,那么所有的操作都会关注同一个内存块,希望能够维护这块内存,这就是一种典型的竞争形式。但在同一时间,只有一个人能够修改这块内存,因此当有一个人在修改时,其他所有想修改的人只能处于等待状态。
下面通过创建正常序列和18C的扩展序列作为索引,验证18C扩展序列的优势。
正常序列索引演示
数据准备
conn autoidx/autoidx
drop table zsdba_idx_seq_normal purge;
-- create table
create table zsdba_idx_seq_normal(id number(20) not null,name varchar(20));
-- create/recreate primary, unique and foreign key constraints
alter table zsdba_idx_seq_normal add constraint pri_id_normal primary key (id);drop sequence test_seq_normal;
create sequence test_seq_normal
minvalue 1
maxvalue 9999999999999999999
start with 1
increment by 1
cache 2;create or replace procedure p_task_idx_seq_normal is
beginfor i in 1 .. 50000 loopinsert into zsdba_idx_seq_normal values(test_seq_normal.nextval,i);end loop;
end;
/
enq: TX - index contention事件统计–之前
col inst_id for 999
col event for a35
col total_waits for 999999999
col time_waited_micro for 99999999
set linesize 200
select t.inst_id,t.event,t.total_waits,t.time_waited_micro from gv$system_event t where t.event = 'enq: TX - index contention';INST_ID EVENT TOTAL_WAITS TIME_WAITED_MICRO
------- ----------------------------------- ----------- -----------------2 enq: TX - index contention 14167 234407171 enq: TX - index contention 22364 42026275
测试数据运行
declarev_job_no number;
beginfor v_parallel in 1 .. 10 loopdbms_job.submit(job=>v_job_no,what=>'p_task_idx_seq_normal;');commit;end loop;
end;
/
enq: TX - index contention事件统计–之后
col inst_id for 999
col event for a35
col total_waits for 999999999
col time_waited_micro for 99999999
set linesize 200
select t.inst_id,t.event,t.total_waits,t.time_waited_micro from gv$system_event t where t.event = 'enq: TX - index contention';INST_ID EVENT TOTAL_WAITS TIME_WAITED_MICRO
------- ----------------------------------- ----------- -----------------1 enq: TX - index contention 25883 510538262 enq: TX - index contention 17838 32869104
测试分析
统计测试前后的enq: TX - index contention差集
INST_ID EVENT 插入前 插入后 插入前 插入后等待数 等待数 等待时间 等待时间
------- --------------------------- -------- ------------------- ------------2 enq: TX - index contention 14167 17838 23440717 328691041 enq: TX - index contention 22364 25883 42026275 51053826
enq: TX - index contention等待次数(25883+17838)-(22364+14167)=7190
enq: TX - index contention等待时间(51053826+32869104)-(42026275+23440717)=18455938
扩展序列索引演示
数据准备
conn autoidx/autoidx
drop table zsdba_idx_seq_scale purge;
-- create table
create table zsdba_idx_seq_scale(id number(20) not null,name varchar(20));
-- create/recreate primary, unique and foreign key constraints
alter table zsdba_idx_seq_scale add constraint pri_id_scale primary key (id);drop sequence test_seq_scale;
create sequence test_seq_scale
minvalue 1
maxvalue 9999999999999999999
start with 1
increment by 1
cache 2
scale;create or replace procedure p_task_idx_seq_scale is
beginfor i in 1 .. 50000 loopinsert into zsdba_idx_seq_scale values(test_seq_scale.nextval,i);end loop;
end;
/
enq: TX - index contention事件统计–之前
col inst_id for 999
col event for a35
col total_waits for 999999999
col time_waited_micro for 99999999
set linesize 200
select t.inst_id,t.event,t.total_waits,t.time_waited_micro from gv$system_event t where t.event = 'enq: TX - index contention';
INST_ID EVENT TOTAL_WAITS TIME_WAITED_MICRO
------- ----------------------------------- ----------- -----------------2 enq: TX - index contention 17966 329764621 enq: TX - index contention 25920 51084690
测试数据运行
declarev_job_no number;
beginfor v_parallel in 1 .. 10 loopdbms_job.submit(job=>v_job_no,what=>'p_task_idx_seq_scale;');commit;end loop;
end;
/
enq: TX - index contention事件统计–之后
col inst_id for 999
col event for a35
col total_waits for 999999999
col time_waited_micro for 99999999
set linesize 200
select t.inst_id,t.event,t.total_waits,t.time_waited_micro from gv$system_event t where t.event = 'enq: TX - index contention';
INST_ID EVENT TOTAL_WAITS TIME_WAITED_MICRO
------- ----------------------------------- ----------- -----------------2 enq: TX - index contention 18374 344437281 enq: TX - index contention 26050 53756689
测试分析
统计测试前后的enq: TX - index contention差集
INST_ID EVENT 插入前 插入后 插入前 插入后等待数 等待数 等待时间 等待时间
------- ----------------------------------- --------------- ------- --------- 2 enq: TX - index contention 17966 18374 32976462 34443728 1 enq: TX - index contention 25920 26050 51084690 53756689
enq: TX - index contention等待次数(26050+18374)-(25920+17966)=538
enq: TX - index contention等待时间(53756689+34443728)-(51084690+32976462)=4139265
总 结
从测试数据分析,正常序列作为索引,在高并发的场景下,enq: TX - index contention等待次数7190,等待时间18.5s,扩展序列作为索引,在高并发的场景下,enq: TX - index contention等待次数538,等待时间4s,无论是从等待次数和等待时间都有大幅度的提升,而且随着并发的增大,扩展序列的优势会更加扩大化。由此可见,在18C的新特性中,Oracle真的用心良苦。
墨天轮原文链接:https://www.modb.pro/db/85028(复制链接至浏览器或点击文末阅读原文查看)
关于作者
张帅,工作9年,其中DBA相关工作经验5年。中国DBA联盟成员,拥有OCP、OBCA证书。现负责公司Oracle、MySQL数据库方面的技术工作;负责Weblogic、WAS、Tomcat等中间件方面的技术支持;掌握SQL编程、Python编程,以及各种压力测试工具和ETL工具使用方法。服务的客户包含银行、证券、医疗、政府等单位。
END
推荐阅读:267页!2020年度数据库技术年刊
推荐下载:2020数据技术嘉年华PPT下载
2020数据技术嘉年华近50个PPT下载、视频回放已上传墨天轮平台,可在“数据和云”公众号回复关键词“2020DTC”获得!
你知道吗?我们的视频号里已经发布了很多精彩的内容,快去看看吧!↓↓↓
点击下图查看更多 ↓
云和恩墨大讲堂 | 一个分享交流的地方
长按,识别二维码,加入万人交流社群
请备注:云和恩墨大讲堂
点个“在看”
你的喜欢会被看到❤
Oracle-索引分裂研究相关推荐
- oracle数据块过热,Oracle索引技术研究
Oracle索引类型 B树索引 特定类型索引 确定索引列 主键和唯一键值列的索引 外键索引 其他合适的索引列 B树索引 B树索引算法 B树是指B-tree(Balanced Tree),B树的存在是为 ...
- 资源放送丨《Oracle数据库索引分裂详解》PPT视频
点击上方"蓝字" 关注我们,享更多干货! 前段时间,墨天轮邀请数据库资深专家 孙加鹏 老师分享了<Oracle数据库索引分裂详解>,在这里我们将课件PPT和实况录像分享 ...
- 本周两场直播丨通过源码了解openGauss多线程架构;Oracle数据库索引分裂详解。...
1.管中窥豹之通过源码了解openGauss多线程架构-8月18日20:00 本讲座主要介绍openGauss的多线程架构,通过源码了解线程间通信机制.线程池的原理和优势.如何开启线程池等,力图通过多 ...
- 《高并发Oracle数据库系统的架构与设计》一2.4 索引分裂
本节书摘来自华章出版社<高并发Oracle数据库系统的架构与设计>一书中的第2章,第2.4节,作者 侯松,更多章节内容可以访问云栖社区"华章计算机"公众号查看 2.4 ...
- Oracle索引树的结构
关于Oracle索引树的结构以及它们对Oracle性能调优是否重要存在大量的.激烈的争论,而且已经有很多文章试图来描述这些重要的Oracle性能工具的内部工作机制.关于这个论题也出现了一些新书,例如由 ...
- oracle索引的监控
最近的研究发现 Oracle 数据库所使用的索引从来没有达到过可用索引数的1/4, 或者其用法与其开始设计的意图不相同.未用的索引浪费空间,而且还会降低 DML 的速度,尤其是 UPDATE 和 IN ...
- 数据库索引分裂 问题分析
1.背景描述: 某客户反馈在 18 点 30 分左右出现性能问题,活动会话飙升,业务卡顿. 2.问题分析 通过awr 可以看到大量的索引分裂等待,和并发的事务槽等待,事务槽的并发等待是由于索引分裂阻塞 ...
- oracle 索引基本原理
一.索引基本概念 oracle提供了两种方式:从表中读取所有行(即全表扫描),或者通过ROWID一次读取一行. 如果只访问大数据量表中的5%的行,并且使用索引标识需要读取的数据块,这样话费的I/O较少 ...
- [转载]oracle索引的简单总结
原文地址:oracle索引的简单总结作者:kindle 一.索引的概念: 数据库的索引类似于书籍的索引.在书籍中,索引允许用户不必翻阅完整个书就能迅速地找到所需要的信息.在数据库中,索引也允许数据库程 ...
最新文章
- 你知道前端单页面路由是怎么实现的吗?
- Windows Phone 7 学习网址总结
- xml读取异常Invalid byte 1 of 1-byte UTF-8 sequence
- android 爆炸动画,一个可以给view显示粒子爆炸/绽放效果的android库 Bloom
- 账号类型_2019年头条、百家、大鱼、企鹅四平台哪种类型的账号最受欢迎?
- zabbix安装及简单配置
- JAVA学习笔记001---认识了解NIO
- lua mysql 存储类型_Lua学习----Lua基础数据类型
- Unicode与UTF8:字符集与字符编码的关系
- Leetcode 刷题笔记(十八) —— 二叉树篇之二叉搜索树的修改与构造
- python执行shell脚本报错_详解python执行shell脚本创建用户及相关操作
- 遇见未知的自己 - 张德芬
- 计算机主机自动关机如何设置,电脑怎么设置自动关机?电脑自动关机方法教程 电脑维修技术网...
- iOS - 手机摇一摇
- 服务器光纤信号灯,光纤收发器的六个指示灯都代表什么?
- 8421码、5421码、2421码及余三码
- DNS对网络连通性的影响
- 简单的小青蛙跳一跳问题
- 某脑残公司领导:80 后就该滚出 IT 行业!二哥第一个不服!!!!!
- pdd实现主图详情图片一键下载
热门文章
- openstack用户列表_什么是OpenStack超级用户?
- (17)css3新增背景属性
- JMeter4.0使用笔记 使用Badboy录制脚本,使用代理录制脚本
- Bootstrap 分页导航
- windows防火墙ntp服务器_NTP教学续集已发送,请你查收!
- 手机距离传感器坏了有什么影响_适合手机兼职的工作有什么影响吗
- C语言怎么给程序加上版本号,给自己的程序加上行号
- yamlcpp遍历_gf-cli 命令行工具
- C#学习笔记_12_枚举结构体
- Day7:html和css