|
100pub币
好久没有发贴了,今天比较清闲发一个前两天弄得case。
客户的一个应用程序报告速度过慢。运行了reorgchk发现F2太高,超过了60%竟然,做了reorg以后,几个小时同样的问题继续出现,F2总是在reorg之后一段时间窜上去居高不下,而应用程序的batch job也从正常的30分钟变成了将近两个小时。
客户说,他们的这个表平时每周都会reorg一次,这次不知道怎么回事不停地overflow。
下面是结构
- Column Type Type
- name schema name Length Scale Nulls
- ------------------------------ --------- ------------------ -------- ----- ------
- REQ_ID SYSIBM INTEGER 4 0 No
- FEED_ID SYSIBM CHARACTER 10 0 No
- CORREL_ID SYSIBM CHARACTER 51 0 No
- REQ_ISS_TS SYSIBM TIMESTAMP 10 0 No
- SYSTEM_ID SYSIBM CHARACTER 3 0 No
- STA_CD SYSIBM CHARACTER 3 0 No
- ISS_CT SYSIBM DECIMAL 3 0 No
- UPDT_TS SYSIBM TIMESTAMP 10 0 No
- SERV_ID SYSIBM VARCHAR 48 0 No
- DATA_TX SYSIBM VARCHAR 15000 0 No
- RESP_DATA_TX SYSIBM VARCHAR 15000 0 Yes
- DATA_IMG SYSIBM BLOB 1048576 0 Yes
- ACT_TRK_GRP_ID SYSIBM CHARACTER 10 0 Yes
- BATCH_NO SYSIBM INTEGER 4 0 Yes
- PRI_POINT_NO SYSIBM SMALLINT 2 0 Yes
- TGXPR01 T8781CUFE_N01 P 4 +REQ_ID+CORREL_ID+FEED_ID+REQ_ISS_TS
- TGXPR01 T8781_IDX1 D 1 +CORREL_ID
复制代码
该表类似于一个session table。并发应用程序首先向表里面写入一条数据,然后调用外部的函数得到一些 XML数据然后插入DATA_TX和RESP_DATA_TX中。
而变慢的是一个Stored Procedure。那个SP主要反复调用一个查询:
- SELECT DISTINCT T8781.TRK_ID,T8781.FEED_ID,T8781.PRI_POINT_NO
- FROM TGXPR01.T8781_REQ_TRK_CUFE T8781
- WHERE (T8781.STA_CD = 'RTO' OR T8781STA_CD = 'RQS' OR
- T8781.STA_CD = 'RRJ') AND (T8781.ACT_TRK_GRP_ID = '0' OR
- T8781.ACT_TRK_GRP_ID IS NULL) AND NOT EXISTS
- (SELECT DISTINCT REQ_ID,FEED_ID
- FROM TGXPR01.T8781_REQ_TRK_CUFE
- WHERE REQ_ID = T8781.REQID AND FEED_ID = T8781.FEED_ID
- AND (STA_CD = 'WFR' OR STA_CD = 'RNC' OR STA_CD =
- 'RIP'))
- ORDER BY PRI_POINT_NO
- fetch first 1000 rows only
- with UR
复制代码
第一个问题,各位能够想象出来为什么OV会那么高吗?
很显然,对于这个应用程序设计,OV高基本是必然的结果,因为它的工作流程是首先写一条数据,在那两个VARCHAR(15000)上面为空,然后向记录里面update两个很大的string。这样在一个高并发的系统中,一个page可能很快就被几十个很小的记录填满,当应用程序UPDATE数据时,该页则没有可以使用的空间,从而使string overflow到另外的页上。
这点比较好理解。
下一个问题,为什么overflow会对该SQL造成影响?
要知道这条SQL里面并没有调用两列中的任意一列,为什么该查询还会受到影响呢?
所以说,我们要抓什么数据?自然是db2expln了(别忘了这个可是SP,并不是动态查询,所以想到db2exfmt的面壁去)
- RETURN
- ( 1)
- |
- UNIQUE
- ( 2)
- |
- NLJOIN
- ( 3)
- /----/ \---\
- TBSCAN FETCH
- ( 4) ( 3)
- | |
- SORT IXSCAN
- ( 5) ( 3)
- | |
- FETCH Index:
- (----) TGXPR01
- /----/ \ T8781CUFE_N01
- RIDSCN Table:
- ( 7) TGXPR01
- | T8781_REQ_TRK_CUFE
- SORT
- ( 8)
- |
- IXSCAN
- ( 9)
- / \
- Index: Table:
- TGXPR01 TGXPR01
- T8781CUFE_N01 T8781_REQ_TRK_CUFE
复制代码
为什么这个plan会受到OV的影响呢?
首先我们来看一看这个plan是怎样工作的。从左下角开始看,首先一个IXSCAN+SORT+RIDSCN,很明显是list prefetching,也就是拿到了RID以后根据RID排序,然后做prefetch。
prefetch是怎样prefetch的呢?也就是把RID列表中所有的row都要读出来,然后一边读一边对这个结果集作TBSCAN,出来的东西按照ORDER BY PRI_POINT_NO排序一下再TBSCAN,完了以后和另一个IXSCAN做NLJOIN,最后得到结果。
怎么样?看出瓶颈了吗?
很明显瓶颈就是那个PREFETCH嘛。在FETCH每一行的时候,db2都需要找到那一行的所有数据。当OV很多的时候会发生什么呢?
DB2说:给我page 12345
然后OS乖乖地把page 12345给了db2
db2然后在page 里面找到了所要得那一行,但是突然发现,有两个列的数据竟然在别的page上。
这样db2又说了:给我page 00038,然后再给我45678
这样I/O继续乖乖地读了两页出来,db2满意了,继续看下一个RID,但是发现下一行数据竟然还有东西在别的page上……
这样就是为什么即使查询里面没有这两列,OV也会对性能造成负面影响。
好了,既然知道了发生了什么事情,下一个问题就是……
实际上是下两个问题:
1)为什么OV再这一段时间内频繁发生?
2)怎样修复它
不知道大家对1)有什么好的见解。至少俺从db2上看不到任何东西能够给出答案。
根据我们上面谈到的OV的产生原因,很显然DB2自己对OV是不能做任何判断的。它只是接受用户的update请求,当发现page里面没有地方的时候就把数据放到别的page,所以这个答案需要仔细研究应用程序在这段时间来得异常行为。我们在这里不做讨论。
对于2),不知道各位兄台有什么妙招呢?(不一定非要从db2来解决,假设如果你是系统架构师,有权利修改整个框架,你要怎样解决才能做到cost最少最安全呢?同时不要忘了也许有别的查询在这个表上存在类似的问题)
100PB象征性奖励最有价值和创造性的答案
回答时请不要只给出方案,需要给出为什么这样做,有什么好处,有什么缺点(很多方案都是复合方案,这个case很难用一个改变就解决所有问题)。 |
最佳答案
查看完整内容
You're not caching every LOBs at the same time, are you? My understanding of your case is that the SP is suffering from excessfive overflow, so you don't want those VARCHAR fields to adversely affect the SP. The access to VARCHAR fields is limited.
|