分类: Oracle
2010-07-20 09:53:14
实际上今天要讨论的内容在之前也零零星星讨论过,只是想通过今天的讨论,加深大家的印象。热块冲突是最为常见的现象,是DBA讨论最多的,不过也是DBA做的最少的部分。几乎所有的系统都存在热块冲突的问题,只是严重程度不同而已,一般系统的热块冲突对系统造成的影响都小于5%,因此绝大多数DBA对此采取了容忍的态度。实际上大多数的热块冲突都可以通过应用方面的优化来解决。解决热块冲突最为有效地方法除了修改SQL外,就是通过调整表的存储结构来解决。
为了探讨今天的话题,我们首先需要了解一下什么是热块冲突,热块冲突有哪些形式。首先要声明的是,本节的讨论时围绕着表这个话题的,解决热块冲突的方法有很多,我们会在今后的很多话题中再次讨论热块冲突,在这里我们主要讨论如何通过优化表的结构来减少热块冲突。
谈到热块冲突我们首先需要了解热块冲突发生的原因,这一点从Oracle对buffer busy waits这个等待事件的定义上可以看出一些端倪:
Buffer Busy Waits ID's and MeaningsBUFFER BUSY WAITS等待事件的三个参数中的前两个是文件号和数据块号,第三个参数8.0-9.2都是等待原因,从10.1开始,第三个参数的含义变成了block的类别(BLOCK CLASS#)。一般来说,buffer busy waits产生的主要原因有几个方面:
Reason Code (Id) Reason <=8.0.6 8.1.6-9.2 >=10.1 0 0 n/a A block is being read 1003 100 n/a We want to NEW the block but the block is currently being read by another session (most likely for undo). 1007 200 n/a We want to NEW the block but someone else has is using the current copy so we have to wait for them to finish. 1010 230 n/a Trying to get a buffer in CR/CRX mode , but a modification has started on the buffer that has not yet been completed. 1012 - n/a A modification is happening on a SCUR or XCUR buffer, but has not yet completed 1012 (dup.) 231 n/a CR/CRX scan found the CURRENT block, but a modification has started on the buffer that has not yet been completed. 1013 130 n/a Block is being read by another session and no other suitable block image was found e.g. CR version, so we wait until the read is completed. This may also occur after a buffer cache assumed deadlock. The kernel can't get a buffer in a certain amount of time and assumes a deadlock. Therefore it will read the CR version of the block. This should not have a negative impact on performance, and basically replaces a read from disk with a wait for another process to read it from disk, as the block needs to be read one way or another. 1014 110 n/a We want the CURRENT block either shared or exclusive but the Block is being read into cache by another session, so we have to wait until their read() is completed. 1014 (duplicate) 120 n/a We want to get the block in current mode but someone else is currently reading it into the cache. Wait for them to complete the read. This occurs during buffer lookup. 1016 210 n/a The session wants the block in SCUR or XCUR mode. If this is a buffer exchange or the session is in discrete TX mode, the session waits for the first time and the second time escalates the block as a deadlock and so does not show up as waiting very long. In this case the statistic: "exchange deadlocks" is incremented and we yield the CPU for the "buffer deadlock" wait event. 1016 (duplicate) 220 n/a During buffer lookup for a CURRENT copy of a buffer we have found the buffer but someone holds it in an incompatible mode so we have to wait.
l 访问某个数据块的时候其他会话正在将该数据块读入db cache,如果IO系统存在性能问题,那么会加重这种类型的等待。
l 访问某个数据块的时候,这个数据块被其他会话以不兼容的模式所持有
产生等待的BUFFER可能是段头(Segment Header),也可能是数据块,UNDO数据块等。段头可能由于大量的并发插入导致freelists的等待或者ASSM下段头里的位图块(bmb block)等待。对待每种类型的buffer busy waits我们的处理方法也是不同的。
对于SEGMENT HEADER的等待,一般来说主要集中在FREELISTS或者BMB上,我们可以通过调整FREELISTS,FREELIST GROUPS等参数来解决。如果等待集中在BMB上,那么一般来说只能通过使用分区表或者调整应用等手段来解决了。本节我们重点讨论如何减少表数据块上的热块冲突。
说起解决数据库热块冲突的办法,实际上我们有两条路,第一条路是从应用的角度减少热块冲突,第二条路是减少热块对系统的影响。在任何一个系统中,热块冲突是避免不了的,因此我们在日常做优化的时候,首先应该考虑是否有可能减少热块冲突带来的影响。顺着这个思路,我们可以发现实际上有一些这方面的手段,比如提高DB CACHE的命中率(一般通过加大DB CACHE的大小来实现)、使用多缓冲区技术等等。在我经历过的案例中,至少有30%的案例是通过上述手段就解决了问题的。采用这些手段解决问题代价比较小,不需要花大力气去分析应用。
前面我们也讨论过,增加INITRANS参数可以有效避免由于事务槽等待而产生的热块冲突。加大PCTFREE的值,可以使每个数据块存储的记录数减少,从而减轻热块冲突。比加大PCTFREE更为彻底的方法是将表存储在BLOCK_SIZE更小的表空间上。
如果数据块本身存在热点怎么处理呢?这个问题回答起来有点麻烦,因为既然是数据,那么数据就是多样性的,没有一种办法是能够解决问题的灵丹妙药。除了我们刚才所说的方法可以缓解热块冲突外,oracle还提供了一系列的手段。最为典型的是hash分区表和hash簇表。
HASH分区表是解决热块冲突的一种较为常用的办法,对于表数据量较大的情况,可以考虑采用HASH分区表。比如有一张表,主键是通过SEQUENCE产生的,那么在没有使用HASH分区表的情况下,同一个时间点产生的记录存储在同一个数据块中的可能性很大。而这些数据随后又被其他应用使用,这样产生热块的机会就很高了。如果我们将这张表根据主键设计成HASH分区表,那么同一个时刻产生的记录就被HASH算法分布到不同的表分区中去了,访问这些数据的时候就可以从多个数据块中读取,从而缓解了热块冲突。
既然HASH分区表这么强,很定有些朋友会蠢蠢欲动了,干脆我把存在热块争用的表都设计成HASH分区表好了。实际上任何技术都有其两面性,HASH分区表解决了热块冲突的问题,但是带来了另外一个问题,如果我们的应用总是通过主键来访问这张表的数据,那么这种方式确实是最好的。但是如果我们还有大量的应用需要根据主键进行范围扫描,或者按照记录的生成日期进行范围扫描,那么HASH分区表的弱点就显现出来了。原本放在同一个数据块中的数据被HASH 算法分散开了,这同时意味着我们对这些数据做范围扫描的时候需要扫描更多的数据块。这就是HASH分区表的弱点,增加了范围扫描的成本。
在实际的生产环境中,我们可能不总是那么幸运,我们肯定会碰到两方面的需求。一方面是热块冲突必须解决,另外一方面可能我们还存在一定的应用要对这些数据做范围扫描。在这种情况下,我们必须进行综合的评估,到底哪种需求是主要需求。如果我们优化范围扫描对系统更为有利,那么我们就必须放弃HASH分区;如果解决热块冲突更为重要,那么我们就必须牺牲范围扫描。实际上Oracle就是这样的,任何技术都是矛盾的,都是有缺陷的,否则我们就只需要记住一些准则,就可以成为大师了。Oracle的大师不是那么容易当的,因为在绝大多数情况下,没有永恒的准则。