关于Freelists和Freelist Groups的研究_第1页
关于Freelists和Freelist Groups的研究_第2页
关于Freelists和Freelist Groups的研究_第3页
关于Freelists和Freelist Groups的研究_第4页
关于Freelists和Freelist Groups的研究_第5页
已阅读5页,还剩13页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

关于 Freelists 和 Freelist Groups 的研究一什么是 freelists本文在于探讨 Freelists 和 Freelist Groups 的作用,存取机制,争用诊断和优化方法,同时通过理论和测试来推翻一些存在了很久的错误观点。本文的读者应该具有较深入的Oracle 知识,对于一般的开发人员这篇文章可能并没有太多的帮助。我们知道 Oracle 数据库的读取单位是数据块(Block) ,而一个 Block 是否允许被写入数据是基于一定的空闲度,这就是大家知道的 pctfree 和 pctused 存储参数设置。假设 pctfree=10, pctused=40,这就表明当一个 Block 的空间使用率达到了 90%(100-pctfree)时,这个 block 就不再允许被用于新增数据( insert) ,而保留下来的这 10%的空间则被预留为行更新(update )所可能需要的空间扩展,我们说此时这个 block 就从freelist 上被摘走了(实际上还有另外一种情况,就是当块剩余空间不足以插入一条记录并且该块的使用率已经超过了 pctused 定义的值并且该块位于 freelist header 处时,该块也会从 freelist 上被摘走,术语称为 UNLINK) 。当有数据删除(delete)的时候,只有该 block 中的数据被删除到一定的程度,该块才会重新被加入到 freelists 中,而这个程度就是 pctused 参数定义的数值,如我们这个例子中,只有块中的数据降低到 40%以下的时候,该块才被重新允许用于新增数据。通过上面的描述,可以知道所谓 freelists,就是一个指定了所有可以用于 insert 操作的数据块的列表。存在在这个列表中的数据块才能用于 insert 操作,一旦一个数据块无法用于insert(达到了 pctfree 参数指定的限度)则立刻从这个列表中被摘除。freelists 的作用就在于管理高水位标志(HWM)以下的空闲空间。注意:freelists 只是管理高水位标志以下的空闲空间,而 实际 上一个 segment 可用的空闲空间包括两种类型:1 已经分配给这个 segment 但是从来未被使用过的位于高水位标志之上的 blocks2 位于高水位标志之下,被 链接在 freelists 上的 blocks至于 freelist groups 的概念和作用,在下面的章节适当的地方会解释。二freelists 是否已经过时随着 Oracle9i 的推出,对于空闲块的管理变得更加智能和有效率了。在 LMT(Locally Managed Tablespaces)中如果指定了 ASSM(Automatic Segment Space Management) ,那么对于任何 pctused,freelists,freelist groups 存储参数的指定都将被忽略。创建ASSM 表空间的方法如下:CREATE TABLESPACE lmtbsb DATAFILE /u02/oracle/data/lmtbsb01.dbf SIZE 50MEXTENT MANAGEMENT LOCAL SEGMENT SPACE MANAGEMENT AUTO;ASSM 得益于使用位图(bitmaps)来管理段中的空闲块,至于具体是如何管理的,那又是另外一篇文章了。就此意义上来说,对于 freelists 的探讨确实可能已经有些过时了,但是首先并不是所有的数据库现在都已经升级到了 Oracle9i,甚至在最需要调整的一些大型应用上往往都由于业务的稳定性而不愿意冒升级到新版本的危险;其次即使是新的应用使用了 Oracle9i 数据库,如果数据库管理员在创建表空间的时候没有明确指定 SEGMENT SPACE MANAGEMENT AUTO,那么默认情况下仍然会使用 Freelists 和 Freelist Groups 来管理 Free Block。所以,在仍然存在有大量 Oracle8i 数据库和非自动段空间管理表空间的现在,对于freelists 的研究仍然具有很实际的意义,而由于默认的 freelists 和 freelist groups 又都只有 1,所以又恰恰是高负载的应用中最需要调整(Tuning)的部分之一。三freelists 存储在哪儿freelists 存储在每个 segment 的 header block 中,我们可以通过 dump 来得到更清楚的认识。dump 在研究 oracle 的内部机制时通常都扮演着很重要的角色。假设我们创建一个表空间 TS_TEST,此表空间是非自动段空间管理的,然后在该表空间中创建 T_MANUAL,T_MANUAL_FREE2,T_MANUAL_FREEGROUP2 三张表。这三张表的 freelists 和 freelist groups 设置如下。SQL select SEGMENT_NAME,SEGMENT_TYPE,FREELISTS,FREELIST_GROUPS from USER_SEGMENTS where TABLESPACE_NAME=TS_TEST;SEGMENT_NAME SEGMENT_TYPE FREELISTS FREELIST_GROUPS- - - -T_MANUAL TABLE 1 1T_MANUAL_FREE2 TABLE 2 1T_MANUAL_FREEGROUP2 TABLE 4 2则可以参照下面的方法对 segment header block 进行 dump 操作。首先先从数据字典中得到存储这个 segment 的文件号和此 segment 的第一个 block 号(也就是 segment header block)SQL select FILE_ID,BLOCK_ID from dba_extents where segment_name=T_MANUAL;FILE_ID BLOCK_ID- -7 9使用 dump 命令转储这个 block 的内容,转储的结果将保存在初始化参数user_dump_dest 指定的目录中。SQL alter system dump datafile 7 block 9;System altered查看 user_dump_dest 目录中的相应 trace 文件,我们可以看到包含如下几行:frmt: 0x02 chkval: 0x0000 type: 0x10=DATA SEGMENT HEADER - UNLIMITED表示这个 block 正是 segment header block。#blocks in seg. hdrs freelists: 2 #blocks below: 2表示位于 freelist 中的数据块有 2 个,在高水位标志(HWM)下的数据块也有 2 个。SEG LST: flg: USED lhd: 0x01c0000a ltl: 0x01c0000b由于我们 dump 的是 TS_MANUAL 表的 header block,而这张表的 freelists=1,所以在dump 文件中看到只有一个 seg lst,这个 freelist 被称为 segment free list 或者 master free list,每个 segment 都至少有一个而且只有一个 master free list(当然是在非自动段空间管理类型下) 。flg( flag)表示该 freelist 是否被使用lhd(list header)表示位于该 list 中的第一个可用 block 的 dba(Data block address)ltl( list tail)表示位于该 list 中的最后一个可用 block 的 dba,这个 block 必定位于 HWM之下。此时我们可以发现 freelists 只是记录了这个 segment 中空闲块的第一个块地址和最后一个块地址,在第一个空闲块的块头处(block header)记录了它之后的下一个空闲块的地址,而下一个空闲块又记录了再下一个空闲块的地址,由此依次记录,一直到最后一个空闲块。Oracle 通过这种链表的方式实现了 freelists 对于空闲块的管理。注意:每次当一个 block 被加入到 free list 中时,该 block 会被放置在 free list 的链表头部。同样我们可以 dump 第一个空闲块来验证上面的链表说法。比如在 lhd 部分记录的 dba 是 0x01c0000a,这是一个 16 进制的数,首先转化为 10 进制,于是得到 29360138。然后通过 oracle 提供的两个函数将块地址转化为可以供我们使用的文件号和块号,以便于我们进行 dump 操作。SQL select dbms_utility.data_block_address_file(29360138) from dual;DBMS_UTILITY.DATA_BLOCK_ADDRES-7SQL select dbms_utility.data_block_address_block(29360138) from dual;DBMS_UTILITY.DATA_BLOCK_ADDRES-10现在我们已经得到第一个空闲块是 7 号文件的 10 号块。用前面提到的转储命令 dump 这个块的内容,我们可以找到下面的内容:fnx: 0x1c0000b表示下一个可用的块地址是 0x1c0000b,在我们的例子这个块正好是可用的最后一个块(segment header block 中的 lhd 部分) ,我们可以再次 dump 这个 0x1c0000b 块,同样查看转储的结果,找到下面的内容:fnx: 0x00x0 表示下面没有可用的空闲块了,也就是表明这是 freelists 中的最后一个空闲块。注意:你们的测试可能得到跟我不一样的转储内容, 这是正常的。四有多少种 free list3 master free list 或者 segment free list简称为 MFL,在 segment 被创建的时候自动生成的,如果我们在创建 segment 时没有指定 freelists 参数,或者指定 freelists=1,都是生成这个 MFL。MFL 对于每个segment 来说有且只有一个(如果指定 freelists1,产生的就是不是 MFL,这一点将在 process free list 部分解释) 。MFL 相当于一个空闲空间池,当一个 segment 被创建时的初始化 block 以及以后动态分配的新 block 都链接到 MFL 中,这个池中的所有空闲块是被所有进程共享的,对于该 segment 有 insert 操作的所有进程都可能会去读取这个 free list,这样当有多个进程要同时 insert 数据时,就可能出现在 MFL 上的争用(MFL 在一个时间只能允许一个进程取得空闲块,当然,其实进程从 MFL 上读取空闲块的操作并不是简单地需要多少就取多少,取得以后就直接向块中插入数据,实际上的过程要更复杂一些,这个过程在进程请求空闲块的过程 部分会有详细描述) 。由此,推出了 freelist groups 的概念,设置 freelist groups 参数大于 1 就是设置了多个MFL,这样就缓解了对于 MFL 的争用。有关 freelist groups 更详细的内容在Super Master Free list部分会有描述。 4 process free list如果进程必须直接从 MFL 中读取空闲块,那么对于 MFL 的争用由 freelist groups 参数解决(设置多个 MFL) ,但是显然还有另外一个思路就是尽量不让进程去直接读取MFL,没有需求自然就无所谓争用。由此引入了另外一个级别的 free list,这就是process free list,简称为 PFL。当我们指定存储参数 freelists1 的时候,生成的就是PFL。我们前面说过 MFL 是在 segment 被创建的时候自动生成的,所以无论是不是有PFL,对于每个 segment 来说都仍然存在 1 个 MFL。也就是如果我们定义 freelists 等于 2 的话,那么在 segment header block 中将总共存在 3 个 freelist,其中 1 个是MFL,另外 2 个是 PFL。这一点我们同样可以通过 dump 转储信息来验证。SEG LST: flg: UNUSED lhd: 0x00000000 ltl: 0x00000000 SEG LST: flg: UNUSED lhd: 0x00000000 ltl: 0x00000000 SEG LST: flg: USED lhd: 0x01c0008b ltl: 0x01c0008b 后面两个 free list 既是 PFL,而前面一个则是 MFL。顾名思义,既然命名为 process free list,那么显然位于这个级别的 free list 中的空闲块只能被一个进程读取。想象一下,如果当前系统对于某张表最多同时会有 10 个进程同时作 insert 操作,那么我们设置 freelists=10,将能尽量满足每个进程都能够使用专属于自己的 free list,无疑通过这样的手段我们缓解了 free list 的争用。一个进程到底会使用哪个 PFL,oracle 内部的算法是:(P % NFL) + 1其中 P 表示 DML 操作进程的 Process ID,可以从 v$process.pid 字段中取得。NFL 表示 freelists 存储参数定义的 PFL 数量。可能会有疑问,如果是这样,多个 MFL 有存在的必要吗?我们只需要设置多个 PFL不就可以了吗?然而事实并非如此,不过请稍安毋躁,在后面讲解进程请求空闲块的过程中会解释这个问题。5 transaction free list在 Oracle 中事务(transaction)是一个重要的概念,每次 DML 操作,事务的开始都是自动的,而我们可以通过 commit 或者 rollback 来标志一个事务的结束。一个进程(或者说一个用户会话)有自己的 PFL,然后一个进程可能会执行很多的事务,于是又出现了这个级别的 free list,这就是 transaction free list,简称为 TFL。TFL 是动态产生的,只有当 DML 语句(比如 delete 或者 update)使 block 占用量降到 pctused 参数指定值之下时才会生成 TFL,一个 TFL 只属于一个事务,而一个事务也只会有一个 TFL,一个事务没有提交之前,此事务的 TFL 上的空闲块不会被其它事务使用。但是可以立刻被本事务使用(此时这些空闲块被称为 previously freed blocks) 。每个 segment 最少可以有 16 个 TFL,同时只要有需求就会动态增加 TFL 数量,除非达到了 segment header block size 的限制。当没有空间允许新的事务得到自己的 TFL 时,这个事务就必须等待其它的事务提交并释放 TFL。等待哪个事务的算法是:(P % NFL)其中 P 表示 DML 操作进程的 Process ID,可以从 v$process.pid 字段中取得。NFL 表示当前的 TFL 总数量。通过 dump 转储数据块信息,我们可以看到类似于下面的内容:XCT LST: flg: USED lhd: 0x01c0008c ltl: 0x01c0008a xid: 0x0008.01f.000003d2其中 xid 表示 transaction id,关于 transaction id 的格式和表示的意义,有兴趣的读者可以查看其它的资料。6 Super Master Free list 或者 Segment Master Free list这个级别的 free list 只有在设置了多个 freelist groups 时才会出现。当我们设置 freelist group1,就会产生 freelist group block,这些 block 紧跟在segment header block 之后,假设我们设置了 storage(freelists 4 freelist groups 2),那么该 segment 的第一个块是 segment header block,第 2,3 个块则都是 freelist group block。首先在 segment header block 中存在 1 个 free list,这个 free list 就被称为 Super Master Free list 或者 Segment Master Free list。而在每个 freelist group block 中又都存着 1 个 MFL,还存在 4 个 PFL,每个 freelist group block 块的剩余空间则全部留给 TFL 使用。在单个 instance 中进程选择 freelist group 的算法是(P % NFB) + 1 。其中 P 表示 DML 操作进程的 Process ID,可以从 v$process.pid 字段中取得。NFB 表示 freelist groups 参数定义的 Freelist Groups 数量。而在 RAC 环境中的算法则更加复杂,本文不作讨论了。查看 freelist group block 的转储文件可以看到类似于下面的内容:frmt: 0x02 chkval: 0x0000 type: 0x16=DATA SEGMENT FREE LIST BLOCK WITH FREE BLOCK COUNTblocks in free list = 5 ccnt = 0 SEG LST: flg: UNUSED lhd: 0x00000000 ltl: 0x00000000 SEG LST: flg: UNUSED lhd: 0x00000000 ltl: 0x00000000 SEG LST: flg: UNUSED lhd: 0x00000000 ltl: 0x00000000 SEG LST: flg: USED lhd: 0x01c00116 ltl: 0x01c0011a SEG LST: flg: UNUSED lhd: 0x00000000 ltl: 0x00000000五进程请求空闲块的过程我们通过对两个事务的描述来说明进程请求空闲块的整个过程。1事务 T1 删除了表 T 中的一些数据,释放了这个 segment 的 block 10 中的一些空间。并且使 block 的已用空间降到 pctused 参数值以下,因此在 segment header block 中产生了一个 T1 的 TFL,而 block 10 被 link 到这个 TFL 中。2事务 T2 想要插入一些数据到表 T 中。但是由于 T1 没有提交,所以 block 10 并不能被T2 使用,而假定 T2 没有作过释放空间(delete 或者 update)的操作,所以 T2 也没有自己的 TFL。2.1T2 开始查找自己的 PFL,尝试找到可以使用的空闲块(术语称为 WALK) 。假设在T2 的 PFL 上有三个 block:block 11,12,13,但是都没有足够的空间满足 T2 的需求。2.2假定 block 11 的已用空间超过了 pctused 参数值,而又由于无法满足 T2 需求,所以从 T2 的 PFL 上被摘除(术语称为 UNLINK) ,同时 free list header 变为下一个 block,也就是 block 12(术语称为 EXCHANGED) ,同样 block 12 不满足需求,又 exchange 到block 13,可惜的是 block 13 也同样不满足需求,于是 T2 的 PFL 上就没有可使用的空闲块了。这个步骤的后台思想是当一个块在搜索空闲块的过程中失败,那么就不应该把这个块再放在 free list header 处。注意:dead block 的出现通常是由于 设置了过高的 pctused 参数导致的。假设我们设置 pctused=90,那么如果由于 update 等原因使一个 block 中的数据占用量降低了90%以下,这个 block 就立刻被重新 link 到 free list 中,但是很可能这一点儿空间根本就不允许 insert 一条记录,又因为此时的 block 占用量仍然位于 pctused 参数值之下,所以即使这个 block 不满足插入一条记录的条件,也仍然被放置在 free list header 处。当进 程需要 free block 的时候,会先查找这些块(默认最多查找 5 个块),如果都不满足 insert 的需求,才尝试提升 HWM。2.3T2 将 PFL 上的所有块都检查过,并且发现没有可用的,此时就停止查询 PFL2.4 Oracle 尝试从 MFL 中移动空闲块到 PFL 中(术语称为 Free Lists Merge) 。移动的块数是一个常量5 个块。如果移动成功,那么从 2.1 步骤重新开始。注意,此时 Oracle 不会去检查其它 PFL,即使在其它的 PFL 上可能会有空闲块。2.5如果上一步中在 MFL 中没有找到可用的块,此时 Oracle 尝试从其它已经提交的事务的 TFL 中获取 block。扫描 header block 中的 TFL entries,查看是否有已经提交了并且链接有空闲块的 TFL。如果找到,所有的空闲块都转移到 MFL 中。然后从 2.4 步骤重新开始。2.6如果上一步失败,Oracle 尝试提升高水位标志(bump up HWM) 。为了减少在segment header block 上的争用, Oracle 每次只提升 m 个 block。m 的算法是:1:如果 HWM1)的情况下,则直接转移到申请空间的进程所拥有的 PFL 上,然后从 2.1步骤重新开始。3事务 T1 准备向表 T 中插入新的记录。首先,它会检索自己的 TFL 上是否有空闲空间。由于 block 10 有可用空间,并且空间满足新纪录的需求,所以 block 10 将会被使用。总结一下上面描述的过程。当重新 insert 数据或者发生 row migration 的时候,会从 TFL header 处开始使用已经释放了的空闲 block。如果 TFL 中没有 previously freed blocks,那么就从 PFL中寻找,因为可能定义了多个 freelist,所以到底从哪个 free list 中找,算法是前面描述过的(P % NFL) + 1。如果在 PFL 中找不到或者根本就没有 PFL(segment 只有一个freelist 的情况) ,那么再从 MFL 中找。仍然找不到的话,返回去再查其它会话的TFL,判断其中的事务是否已经 commit,如果已经 commit 了,则把这个 TFL 的 flag标志为 unused,同时把位于这个 list 中的所有 block 合并到 MFL 中。如果经过上面的步骤,在任何一个级别的 free list 中都没有找到可用的空闲块,此segment 就要提升 HWM,如果提升 HWM 失败,则分配下一个 extent,新分配的block 被 link 到 MFL 或者 PFL 中,重新开始上面的查找步骤。当一个块由于 DML 操作而被重新链接到 free list 中是被放置在 MFL 中的,如果有 PFL 存在,那么在使用前,根据数据请求量,每次最多转移 5 个 block 到相应的 PFL 中,也就是在存在多个 freelist 的情况下,一次空间的请求总是读取 TFL 或者 PFL,而不会直接从MFL 中读取。现在我们可以回答前面的那个疑问了。多个 MFL 有存在的必要吗?我们只需要设置多个 PFL 不就可以了吗 ?从这个地方我们可以看到虽然多个 free list 可以缓解多个并发的 session 同时更新一个segment 时对于 data block 的争用, 但是如果只有一个 main free list,那么在从 main free list 把 block 转移到 process free list 的这个环节上仍然会出现争用,此时就是多个 freelist group 发挥效果的时候了。所以多个 freelist group 不仅对于 RAC 环境有效,对于单个instance 也是可以缓解一定的资源争用的。但是如果有多个 freelist group,就不可避免地会产生空间浪费的副作用,在某些特殊场合下甚至会让一个 segment 急速地增大,为什么会这样,可以参看后面关于 freelist groups的那个比喻。我们可以通过转储 segment header block 来查询 HWM 的位置,然后再查询转储 freelist group blocks 来查询 link 在每个 free list 上的空闲块,如果发现 HWM 的位置很高却又有大量的空闲块,就可能表示这个 segment 经历了不正常的 extent 扩展。块在 free list 间的移动1block 被分配给一个 segment,但是却不存在于 free list 中,因为这个 block 还位于HWM 之上。2当 block 降到 HWM 之下时(bump up HWM) ,这个块就进入 MFL 或者一个 free list group 的 MFL 中。3如果设置了 freelists1,也就是存在多个 PFL 的情况下,block 会进入 PFL。有利于缓解对于 MFL 的争用。4当 block 的可用空间低于 pctfree 定义的值,block 从 free list 中删除。此 block 不再被允许进行 insert 操作。5当一个事务进行了 delete 或者 update 操作,致使 block 的已用空间低于 pctused 定义的值,该块进入这个事务的 TFL,除非事务 commit,否则该块只能被此事务使用。6在寻找 free block 时,空闲块会从 TFL 转移到 MFL7当用户进程需要空闲块时,空闲块又从 MFL 转移到 PFL一关于 free list 将导致大量空间浪费的误解一直以来有的说法是多个 freelist 也可能会导致大量空间浪费,其实这是一个误解。至少从测试和某些更具有权威性的文档来看,多个 freelist 没有太多的空间浪费。回顾一下一个事务请求空间的过程,我们就可以得出结论。1一个 session 需要空间了,先在自己的 TFL 上找,这是在找 previously freed blocks 2找不到,找自己的 PFL3再找不到,找 MFL,如果找到,移动最多 5 个块到自己的 PFL 上,然后重新查找 PFL4如果 MFL 中仍然找不到,返回去找其它会话的 TFL,看看有没有 commit 了的事务,如果有,将这个 TFL 中的 free block 转移到 MFL 上(这个时候其它事务的 free block 就能被这个事务使用了) ,然后重复第三步。5所有的 TFL 上都没有空闲块,查找 Super Master Free List,如果找到,将最多 5 个块转移到 MFL 上,然后重复第三步。6如果找不到,移动 HWM(Bump up HWM) ,如果成功,那么直接将块转移到自己的PFL 上,重新查找 PFL。7如果移动 HWM 不成功,那么分配 extent,也就是分配新的 block,重复第六步。8分配 extent 不成功,最终报错,没有可用的空间。整个请求过程可以参看下图二可见多个 freelist 只是多个 process freelist 而已,而 main freelist 始终只有 1 个,又因为main freelist 是共享的,所有在同一个 freelist groups 中的 process 都可以从这个 main freelist 中取得 free block,而每次取得的空闲块数也最多只有 5 个块,那么也就是一个PFL 下不会链接过多的空闲块,同时当一个事务删除了大量的数据并且 commit 之后,这些空闲块是会归还给 MFL,从而可以被其它事务使用。所以即使是设置了多个 freelist,也并不存在多少浪费空间的问题。当然不论如何,设置了过多的 freelist,终究是会浪费一些 free block(即使可能只是浪费 HWM 之下的几十个 block) ,而且还有一个坏处就是会减少可以分给 TFL 使用的 free list entry,所以比较合适的设置是将 freelists 设置为最多可能同时操作该 segment 的会话数。三对于 freelists 和 freelist groups 的一个比喻对于 freelist 和 freelist group,Tom 在Effective Oracle by Design中有个比喻,非常形象。想象有一台饮水机和源源不断的急需喝水的人们,一台饮水机就代表一个 free list,而一个想喝水的人就是一个准备向 segment 中插入数据的会话。如果我们只有一个饮水机,那么所有想喝水的人都必须要排成一队,然后前一个喝完了下一个才能喝,这就产生了争用。设想一下我们现在放置了 10 个饮水机,很明显人们可以排到 10 个队伍中的任何一个队伍里,毫无疑问效率大大加快了。这时瓶颈又出现了,就是如果一个饮水机里的水被喝完了,就得给这个饮水机加水,此时如果只有一个加水员(这就是一个 freelist group) ,那么加水的速度可能就会跟不上了,添加 freelist group 就是增加加水员,增加到 2 个,每个人负责 5 个饮水机(体现在参数上,是 freelists 5 freelist groups 2) ,OK,效率又提升了。对于空间浪费的负面影响,我们继续设想一下。来了一个十分能喝水的人,他把住一个饮水机不停地喝,喝完了,引水员就加水,又喝完了,又加,即使是其它的 9 个饮水机里都是满满的水也没用,因为这个人一旦从某个送水员管辖下的饮水机中开始喝水,就不会换到另外一个送水员管理的饮水机上去(一个会话一旦从某个 freelist group 的 freelist 中开始读取空闲块,就不会再使用其它 freelist group 中的 freelist,即使其它的 freelist 中还有很多的空闲块) 。四和 freelists 和 freelist groups 相关的等待事件V$SYSTEM_EVENT 视图中记录了从数据库启动以来所有的等待事件信息,通过这个视图我们可以比较清楚地知道数据库经历的最严重的等待到底是哪些。但是一个等待事件可能会是由于各种各样的原因导致的,所以在检查 V$SYSTEM_EVENT视图的同时还需要一些其它视图的辅助,才可以更准确地定位问题所在,比如我们可能还需要去查看 V$SESSION_WAIT,V$WAITSTAT 等视图。跟 freelists 和 freelists groups 相关的等待事件中,比较主要的是 Buffer Busy Waits 事件和 Enqueue 事件。7 Buffer Busy Waits当一个进程需要一个数据块,但是发现这个数据块正在被其它进程读入 buffer cache,或者说这个数据块虽然已经存在于 buffer cache 中但是却处于一个无法共享的状态,此时就经历 Buffer Busy Waits 等待事件。通过检查 V$SYSTEM_EVENT 视图,可以确认系统是否正在遭受严重的 Buffer Busy Waits 事件( TIME_WAITED 字段的值过大,表示等待总时长比较显著) ,但是这还不足以使我们能够判断到底问题出在什么地方,此时就需要再去检查 V$WAITSTAT视图。这个视图中每一行都记录了系统经历的不同类别 block 的等待时间。通常如果我们发现 segment header 类别或者 data block 类别的等待时间显著,那么就很可能是freelists 争用。如果能够明白这两种类别的 block 等待产生的原因,自然就有相应的解决方法了。 首先解释一下为什么会产生 segment header 部分的等待。前文描述过如果没有使用多个 free list group,那么所有的 free lists 都是位于 segment header block 中的。一个进程对于 free list 的操作将持有独占锁,如果多个进程同时请求操作 free list,那么就会产生争用,而这个争用在 V$WAITSTAT 视图中就表现为 segment header 上的等待。那么为什么会产生争用,这又有两种原因。一种是同时要求操作 free list 的进程确实过多,这种情况下我们需要增加 free list。另外一种情况则是实际上同时操作的进程并不多,但是操作 free list 的频度过高,为什么会频繁操作,因为不停地有 block 从 free list 中被摘掉同时又不停有新的 free block 被放入 free list 中,这通常表示我们设置了不正确的 pctfree 和 pctused 参数值,比如 pctused 值和 pctfree 值设置的过近,这种情况下盲目增大 free list 可能并没有什么效果,我们需要作得是设置正确的 pctused 和 pctfree 值。再来解释为什么会产生 data block 部分的等待。因为每个进程对于 free block 的请求都是从 free list header 处开始的,如果 free list 较少,那么无疑就增加了不同的进程取得的 free block 是同一个块的可能性。多个进程又去同时更新一个 block,这就产生了 data block 的等待,这也是我们常说的热点块问题。由于热点块问题,同时在等待事件中可能比较显著的还会有 latch free(Cache Buffers Chains Latches) ,latch 又是oracle 内部的另外一种锁定机制了,本文不再深入解释。增加 free list 可以缓解这个问题,因为每个 free block 只会属于一个 free list,给不同的进程分配不同的 free list 就减少了并发进程同时访问一个数据块的风险。另外设法将被频繁并发访问的 segment 上的数据分布在更多的 block 中也可以缓解这个问题,比如我们可以增加 pctfree 值,以扩大数据分布。但是这就引出了另外一个问题,如何确定哪些数据块是热点块,只有知道了是哪些数据块,才可能知道这些块是属于哪个 segment,才能有的放矢地调整相应 segment 的存储参数或者甚至将整个 segment 转移到另外的数据文件,另外的存储介质上。由此引入另外一个视图,V$SESSION_WAIT。这个视图中存储的是一个会话实时的等待事件,如果我们只是偶尔去检查一次,可能正好捕捉不到 buffer busy waits 事件,所以应该通过计划任务(Oracle JOB 或者操作系统级别的 cron)定时地检查这个视图,将检查结果存入另外的表中,建议可以在系统繁忙期每隔 5 秒或 10 秒运行一次下面的SQL,注意取样的总时间不能过长,因为这个 SQL 对于系统还是有影响的。SELECT /*+rule*/s.username, e.owner, e.segment_name, p1 File#, p2 Block#FROM v$session s, v$session_wait w, dba_extents eWHERE w.event=buffer busy waitsAND s.sid = w.sidAND e.file_id = p1AND p2 between e.block_id and e.block_id +(e.blocks - 1);返回的结果中 username 表示读取这个块的用户名, owner 表示拥有热点块所属segment 的用户名,segment_name 表示热点块所属的 segment 名称,File#表示热点块所处的数据文件号,Block#表示热点块号。注意:如果我们使用 Oracle10g,那么新增的性能 视图V$SESSION_WAIT_HISTORY 将自动保留最近的 10 个会话等待事件的历史信息,通过这个视图可以更简单 地判断问题。如果我们设置了多个 freelist group,那么我们在 V$WAITSTAT 视图中还可能会发现free list 类别的等待,这个等待表示在 freelist group blocks 上产生了争用。注意,只有当设置了多个 freelist groups 时,才可能出现这个类别的 buffer busy waits 等待事件。至于调优的方法可以参看上面的调整手段。8 Enqueueenqueue 也是一种锁(lock) ,只不过是 oracle 用来管理共享内存结构的锁定机制,通过

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论