oracle assm,一个案例读懂ORACLE ASSM机制--技术人生系列第五十七期--我和数据中心的故事...

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,查看其历史执行情况如下:

viewspace-2284118

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

现在,我们就可以把问题精确定义为:“

一个insert语句为什么会在某一时间点产生大量的逻辑读(和物理读)

?”

3

追踪现象

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

viewspace-2284118

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

viewspace-2284118

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

4

“合理”推断

看到这些,我们停下来思考看看刚刚重新定义的问题:“

一个insert语句为什么会在某一时间点产生大量的逻辑读(物理读)

?”从等待事件的情况来看,这个会话一直在读插入目标对象(表),看来并不是在维护表的索引,那它为什么要不断的读这个表里不同的数据块呢?

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

viewspace-2284118

特征:

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

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

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

viewspace-2284118

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

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

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

viewspace-2284118

可以看到,

这个块中剩余空间(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

viewspace-2284118

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

viewspace-2284118

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

viewspace-2284118

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

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

viewspace-2284118

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

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

viewspace-2284118

6.通过10046 event跟踪

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

viewspace-2284118

可以看到,

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

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

viewspace-2284118

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

8.查看当前的位图信息

viewspace-2284118

在新插入记录后,原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,分析解决方案的利弊,选择一个我们可以接受的方案。

本文转载于中亦安图

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值