趣文网 > 作文大全

D57.一个案例读懂ORACLE ASSM机制

2021-01-03 05:40:01
相关推荐

前言

ASSM机制是oracle在段内进行空间自动管理的机制;通常来说,这个机制能很好的帮我们查找、定位、分配相关的段空间;然而,所有的机制都不是那么完美的,在具体的CASE中,我们需要充分理解它,才能更好的掌控它;今天的CASE分享,希望大家能对ASSM机制有真正充分的理解。

1.问题来了

“我们这一个奇怪的问题吧,一个简单的insert语句居然执行了上百秒。”

在一个投产上线后的某一天,负责应用维护的同事描述了他的疑惑;

很快,他展示了应用日志中关于那条insert语句超时的相关信息;很简单的语句,在应用日志中打出了整个SQL文本:

INSERTINTO XXXX_CER(XXXX_CER_ID,XXX_NO,U_ID,XXXX_CER,XXX_CER)

VALUES(RA_SEQUENCE.nextval,:1,:2,:3,:4);

执行时间超过了100S;

“这个语句看起来确实很简单,当天一直在报超时吗?”

“并没有,正常执行都挺快的,当天只是出现了极个别的几条而已,后来好像就没再报了,当时数据库是不是出了什么问题?”

“看起来是有些奇怪,但是具体原因还需要细查;”

2.定义问题

当这样一条SQL摆在你面前,它执行花费了超过100s,你会考虑到造成这一现象的可能因素都有哪些呢?

INSERTINTO XXXX_CER(XXXX_CER_ID,XXX_NO,U_ID,XXXX_CER,XXX_CER)

VALUES(RA_SEQUENCE.nextval,:1,:2,:3,:4);

既然是极个别的出现执行缓慢的情况,那么应该首先应该排除数据库整体性能缓慢导致SQL执行慢的情况;我们很简单的收集一个包含问题时段的AWR报告来看,数据库整体DB Time并不高,也未出现异常的等待事件;

看来还是要针对单个SQL来进行分析;

于是我们在数据库中找到该SQL的sql_id,查看其历史执行情况如下:

可以看到,在问题时段内执行的次数并不多,但是其对应的逻辑读和物理读大大地超过了正常时段,这样执行时间长也就理所当然了;

现在,我们就可以把问题精确定义为:“一个insert语句为什么会在某一时间点产生大量的逻辑读(和物理读)?”

3.追踪现象

有了sql_id(22xzq114gz65j),有了大致的时间段,我们就可以追踪这个语句具体执行过程了;我们来查看数据库活动会话历史中关于该SQL的执行情况:

可以看到,对于单条SQL某一次执行,在活动会话历史的视图中,被采样的次数竟然达到了139次;进一步追踪这条SQL单次执行过程中(指定sql_exec_id)产生的等待:

可以看到,在执行过程中主要出现的等待事件是数据文件的顺序读;而且访问的对象都是XXXX_CER表(对象号为15642);

4.“合理”推断

看到这些,我们停下来思考看看刚刚重新定义的问题:“一个insert语句为什么会在某一时间点产生大量的逻辑读(物理读)?”从等待事件的情况来看,这个会话一直在读插入目标对象(表),看来并不是在维护表的索引,那它为什么要不断的读这个表里不同的数据块呢?

我们不妨先dump在insert过程中不断查找的几个块来看看,这些数据块有什么共同的特征,选取典型的数据块信息如下:

特征:

1.该数据块中存在3条记录;

2.单条记录的长度似乎偏长,每条记录的第3列和第4列的长度达到了1100个字节左右;

看起来这个表似乎还有点特殊,再看一下表的定义:

看到了两个字段的定义长度为4000,似乎一下就找到了一个方向;

试想一下,一个数据块的大小是8192字节,这里的如果插入数据的长度不再是2000字节左右的大小,而是偶然的插入更长的数据,一时间需要找到足够存放该记录的数据块可能需要查找更多的块;

再仔细看看上面块的信息:

可以看到,这个块中剩余空间(avsp available space)大小为0x5f3(十进制1523),也就是说,如果插入的数据记录占用空间大于1523,那么必然无法存放在这个块里,这个块不合适,那么ORACLE将继续寻找下一个合适的块,如果再找到不合适的,继续找,如此反复,那么找的块就多了,对于数据文件的单块物理读也就多了;

感觉好像很合理,不如先与应用维护人员确认插入失败的那条记录是否特别长;

然而,随后应用维护人员给出的答复却出乎我们意料:

“插入失败的记录更短,一般来说列3和列4的列值是同样的数据,长度都是1100字节左右,单条记录的总长度在2200字节左右,而插入失败的记录则是只有列3有数据,而列4则为空值,也就是说插入失败的记录总长度应该在1100字节左右!”

看似合理的的推断,好像又没有得到证据支持,再次陷入沉思;

5.深入思考

再仔细回过头来思考,大的方向应该没有错,只是思路并没有特别清晰;我们重新捋一下过程,再来看看分析过程中的几个重点:

1.通常情况下,插入的记录长度在2200字节,而在插入2200字节的记录时并没有像插入更短长度记录时需要查找那么多块,为什么需要空间更小反而需要查找更多的块?

2.对于找到的剩余空间还有1523字节的块,为何在插入大约1100左右字节的记录时,仍然无法将数据插入到这个数据块中呢?

再将问题转换一下:

1.ORACLE在插入数据时,是如何查找到“合适剩余空间”的块的?

2.ORACLE在查找到“合适剩余空间”的块时,是如何判定能否真的能插入到该块中呢?

把上面两个问题想清楚了,这里的问题似乎也就应该明了了。

6.理解ASSM

要想想清楚上面两个问题,需要先理解ORACLE的ASSM机制;

在ASSM机制中,存在一个位图的概念,它是一个二进制的数组,能够迅速有效地管理存储扩展和剩余区块(free block),每个块有多少剩余空间根据位图的状态来确定,其标志位的状态包括包括unformatted,0-25% free, 25-50% free, 50-75% free, 75-100% free和FULL;

另外需要注意的一点是,ASSM中还有一个PCTFREE的概念,该值为保留空间百分比,表示数据块在什么情况下可以被insert,默认是10,表示当数据块的可用空间低于10%后,就不可以被insert了,只能被用于update;即:当使用一个block时,在达到pctfree之前,该block是一直可以被插入的;

理解了上面的ASSM机制,我们可以很清楚的回答上面的两个问题了:

1.ORACLE在插入数据时,是如何查找到合适剩余空间的块的?

答:通过ASSM的位图信息来查找到合适的剩余空间;对于8192的数据块,如果需要插入长度为2200字节的数据记录,那么ORACLE需要寻找25-50% free及以上的数据块;而如果插入的是1100左右字节的数据记录,那么只需要寻找0-25%free及以上的数据块即可;

2.ORACLE在查找到合适剩余空间的块时,是如何判定能否真的插入到该块中呢?

答:以本案例为例,需要插入1100左右字节的数据记录,查找到0-25% free的数据块,比如前面dump的剩余空间为1523字节的块就是这样的数据块;但是实际上,还需要考虑保留10%也就是819(也就是8192*10%,PCTFREE部分)的空间,那么该块真实可以插入的数据记录的最长长度应该在1523-819=704字节左右;当然也就无法插入1100字节的数据记录;

7.逻辑推演

依据上面两个问题的回答,我们可以理解这样一种情况:

1)在大多数情况下, 我们插入记录长度为2200字节记录时,总体来说,段中单个数据块基本保存3条记录;

2)当一个数据块中存在三条记录后,块空间的剩余大小大约在8192-2200*3=1592字节左右;

3) 剩余1592字节左右的块,在位图中会被标记为0-25%free;

4) 在不断继续插入2200字节的记录时,因为2200字节超过了8192的25%,显然ORACLE不会试图去使用0-25%free的数据块,而是会使用更高free的数据块或者开辟新的数据块;

5)于是,段中存在大量0-25%free的数据块,实际上这些块的剩余空间约在1600字节左右;

6)当需要插入一条长度为1100字节的记录时,ORACLE认为0-25% free的块是适合存放这些记录的,然而实际上最终因为实际剩余空间的大小和PCTFREE的原因,这些块并不能存放下这条记录,于是继续寻找这类数据块;

上面的过程,基本就能描述insert过程出现大量数据文件顺序读等待事件的情况;

那么,照上面的逻辑,我们会问,现在我们只要插入长度为1100字节的记录,就还会需要长时间的找合适的数据块,长时间的出现数据文件的顺序读等待吗?答案是否定的!因为,在寻找到一个0-25% free的数据块而无法将数据插入到该块之后,ORACLE就会将块的位图信息更新为full状态(尽管块中可用空间还有1500字节),后续插入记录就不会再来试图使用该数据块,即不再出现执行缓慢的情况;也就是说,上述情况出现过一次之后,大量的块会被置为full状态;所以这种情况不会出现的非常频繁;

所以,我们遇到的问题的本质就是:ASSM的位图信息只有极少的几种状态信息来标记数据块的剩余空间,不够精准,在极端情况下可能会导致insert/update操作过程中试图去使用并不合适的数据块,导致了大量的数据块读取操作!

8.场景重现

理解了前面的过程之后,其实我们就可以轻易的模拟出上述情况:

1.创建一个表,默认PCTFREE为10

2.插入15条记录,每条记录占空间大小为2200左右;

3.查看当前数据占用的extents数

当前为数据段分配了一个extent,占用8个block空间;文件号4,块号为123904-123911总共8个块。

4.查看当前段的位图信息

可以看到,8个block中,除了3个是元数据block外,其他五个数据块位图信息都显示0-25% free,事实上通过前面的分析,我们也能知道这里每个块中存放了3条记录;

5.准备插入一条1100字节的记录

6.通过10046 event跟踪

在会话级设置10046事件进行跟踪,然后执行刚刚准备的insert操作;

可以看到,简单的insert语句,用单块读的方式遍历了整个表的所有块(等待事件中p2包括了123904-123911);

7.查看当前表占用的extents数

在新插入一条记录时,原有的extent不能存放这条记录,新扩展了一个extent;

8.查看当前的位图信息

在新插入记录后,原0-25% free的块位图信息被更新为full状态;

至此,整个问题的现象已经被完全重现出来,而且理论依据也非常充分了。

9.我们能做什么

首先,我们需要理解,触发上述问题必须要有几个特点:

通常插入的记录长度偏长(25%的块空间不够存放一条记录);偶尔插入的记录长度相对于以往偏短(记录的长度低于块大小的25%)在出现一次上述情况的过程,同时也是“修正”位图信息的过程;

综合来看,触发条件较为特殊,因为有自动修正的过程,触发次数不会太多;

事实上,理解了上述整个过程之后,我们会发现,面对这样的情况,其实可以做的并不多;我们可以做的几点包括:

1.如果可以,在表定义上给字段定义合理的default值,避免出现记录长度大幅变化的情况;

2.如果上述情况出现频繁,可以考虑调整数据库的相关隐含参数,指定ORACLE寻找空块的个数(两个隐含参数大家可以了解下:_assm_high_gsp_threshold和_assm_low_gsp_threshold);

10.总结

分析重现完整个问题,我们能说oracle ASSM机制是存在大问题的吗?其实也不能,从设计上来看,ASSM机制是为了通过有限甚至极少的数据来定位数据块的使用情况,在节省空间的情况下可能会出现极端情况下的性能异常,在设计上这只是一个平衡;如前面的建议,设置隐含参数(_assm_high_gsp_threshold和_assm_low_gsp_threshold),对于这个问题而言可能会有效,但是同样又有可能造成大表/索引出现较严重的空间浪费的情况;所以,对于问题的处理,我们需要在理解原理的基础上结合具体的CASE,分析解决方案的利弊,选择一个我们可以接受的方案。

阅读剩余内容
网友评论
相关内容
延伸阅读
小编推荐

大家都在看

初中开学作文开头 做饭的步骤作文 我看学校新变化作文 忍耐作文 送礼物英语作文 五年级下册各单元作文 让我感动的一个人作文500字 刘翔跨栏作文 关于奥运会的作文 我家的小白兔作文400字 想家作文 武大樱花作文 关于地震作文400字 小书迷作文500字 当兵作文 作文的五大文体 快乐的活动作文 写人的作文的好开头 养蚕宝宝的作文 我不再什么的作文 什么什么的心声作文 环境保护作文200字 心意的作文 我的学校作文350字 看书入迷的作文 可爱的小狗作文300字四年级 我心中的一颗星作文 紫薇花作文300字 三年级作文我 我-了作文