Oracle怎样重用已过期和未过期的 undo extent?

许多 DBA 那里收到的一个常见问题是:undo 表空间几乎已满,如何确定空间会被重用?

首先必须知道有两种撤消管理:自动和手动。
Oracle 建议使用 Auto Undo Managements,因此将重点关注这一点。
当使用Auto Undo Management时,Oracle 管理所有undo段及其extent。 Oracle 使用一些算法来在事务请求时分配空间。回到问题,空间会被重复使用吗?可以说是的。大多数情况下,undo空间(包含expired extent和unexpired extent(如果需要))被重用,唯一的例外是retention guarantee被enable时,但默认情况下不启用。此外,必须确保 Oracle 永远不会重用事务中的Active Extents。

可以通过以下查询查看undo表空间是否启用了retention Guarantee:

select retention from dba_tablespaces where tablespace_name='<tbs_name>';
RETENTION
-----------
NOGUARANTEE

这是unexpired extents不会被reuse的唯一例外,替代的,如果没有其他方法来获得可用空间,则操作将失败。 当禁用retention guarantee时,将采用以下算法。
当我们执行需要分配undo空间的操作时:
1.在没有活动事务的undo段中分配一个extent。 为什么在其他段,而不是当前段? 因为 Oracle 尽可能在所有 undo 段上分布事务,避免事务集中于某几个段而引起竞争。
2.如果没有找到这样的undo 段,那么oracle 会尝试online一个offline的段,并使用它来分配新的extent。
3.如果没offline的undo段可以online,那么 Oracle 创建一个新的undo段并使用它。
4.如果空闲空间不允许创建undo段, Oracle 会尝试重用当前undo段中的expired extents
5.如果失败,Oracle 会尝试重用另一个undo段中的expired extents
6.如果失败,Oracle 会尝试自动扩展数据文件(如果 autoextensible=yes)
7.如果失败,Oracle 会尝试重用当前undo段中unexpired的extent。
8.如果失败,Oracle 会尝试从另一个undo段重用unexpired的extent
9.如果失败,则操作将失败

对于与undo段/范围关联的正在运行的事务,如果它需要更多undo空间:
1.如果当前范围有更多空闲块,则使用已准备好分配给该范围的下一个空闲块。
2.如果当前范围没有空闲块并且如果段的next extent已expired,则将next extent中环绕起来并返回第一个块。
3.如果下一个extent 没有过期,则从UNDO 表空间中获取空间。 如果空闲范围可用,则将其分配给undo段。
4.如果没有可用的空闲范围,则从offline undo段重用。 从offline undo段中释放范围并将其添加到当前undo段。
5.从online undo段中偷。 从online undo段中释放范围并将其添加到当前undo段。
注意:启用retention guarantee的唯一不同是unexpired的范围将不会被重用。

在下面的示例中,将您展示第一个算法的行为,当有一个具有 autoextend=on 和 autoextend=off 的undo空间时
Example 1: Autoextend off
对于此示例,使用 5MB 的undo表空间。 以下数据文件是表空间中唯一的一个:

SQL> select tablespace_name, file_name,autoextensible, bytes/1024/1024 MB from dba_data_files where tablespace_name='UNDOTBS1';

TABLESPACE_NAME FILE_NAME                                  AUT MB
--------------- ------------------------------------------ --- ----------
UNDOTBS1        +DATA/orcl/datafile/undotbs1.264.882411811 NO  5

当在其他会话中执行一些更新时,监视 Undo 范围,想法是查看expired和unexpired的范围将如何被重用

1* select status, count(*) Num_Extents, sum(blocks) Num_Blocks, round((sum(bytes)/1024/1024),2) MB from dba_undo_extents group by status order by status

STATUS    NUM_EXTENTS 
--------- ----------- 
EXPIRED    7 
UNEXPIRED  41

没有Active extents被创建

STATUS    NUM_EXTENTS 
--------- ----------- 
ACTIVE    9 <--There were free extents to use 
EXPIRED   6 <--1 extent was reused
UNEXPIRED 40 <--1 extent already expired

STATUS     NUM_EXTENTS 
--------- ----------- 
ACTIVE    11 <--There were free extents to use 
EXPIRED   6 
UNEXPIRED 40

STATUS    NUM_EXTENTS 
--------- ----------- 
ACTIVE    13 <--There were free extents to use
EXPIRED   6 
UNEXPIRED 40

STATUS    NUM_EXTENTS
--------- ----------- 
ACTIVE    15 <--There were free extents to use
EXPIRED   6 
UNEXPIRED 40

STATUS    NUM_EXTENTS 
--------- ----------- 
ACTIVE    17 <--There were free extents to use
EXPIRED   6 
UNEXPIRED 40

STATUS    NUM_EXTENTS 
--------- ----------- 
ACTIVE    19 
EXPIRED   6 
UNEXPIRED 31 <--unexpired extents were reused

为什么expired的范围没有被重用? 假設正在以 10,000 个为批次执行更新,因此可能已经存在的范围太小而无法分配足够的空间供我的update生成的undo数据使用。 请记住,Undo 表空间范围是自动分配的,因此第一个范围很小(开始时为 64KB)

STATUS     NUM_EXTENTS 
--------- ----------- 
ACTIVE     29 
EXPIRED    6 
UNEXPIRED  29 <--unexpired extents were reused

STATUS    NUM_EXTENTS 
--------- ----------- 
ACTIVE    31 
EXPIRED   6 
UNEXPIRED 27 <--unexpired extents were reused

STATUS     NUM_EXTENTS
 --------- ----------- 
 ACTIVE    33 
 EXPIRED   6 
 UNEXPIRED 25 <--unexpired extents were reused
STATUS     NUM_EXTENTS 
--------- ----------- 
ACTIVE    35 
EXPIRED   6 
UNEXPIRED 23 <--unexpired extents were reused

STATUS    NUM_EXTENTS
--------- ----------- 
ACTIVE    37 
EXPIRED   6 
UNEXPIRED 21 <--unexpired extents were reused

STATUS    NUM_EXTENTS 
--------- -----------
ACTIVE    39 
EXPIRED   6 
UNEXPIRED 19

STATUS    NUM_EXTENTS 
--------- ----------- 
ACTIVE    41 
EXPIRED   6 
UNEXPIRED 17 <--unexpired extents were reused

STATUS    NUM_EXTENTS 
--------- -----------
ACTIVE    43 
EXPIRED   6 
UNEXPIRED 15 <--unexpired extents were reused

STATUS    NUM_EXTENTS
--------- ----------- 
ACTIVE    45 
EXPIRED   6 
UNEXPIRED 13 <--unexpired extents were reused

STATUS    NUM_EXTENTS 
--------- ----------- 
ACTIVE    46 
EXPIRED   6 
UNEXPIRED 12 <--unexpired extents were reused

这时候收到以下错误:
ERROR at line 1:
ORA-30036: unable to extend segment by 8 in undo tablespace 'UNDOTBS1'

这是因为 Expired 和 Unexpired 范围都不足以分配我的undo数据,并且由于表空间已禁用自动扩展,Oracle 引发了一个错误,指出没有找到更多可用空间。 如所见,Oracle 没有调整任何数据文件的大小:

SQL> select tablespace_name, file_name,autoextensible, bytes/1024/1024 MB from dba_data_files where tablespace_name='UNDOTBS1';

TABLESPACE_NAME FILE_NAME                                   AUT MB
--------------- -----------------------------------------  ---  ----------
UNDOTBS1        +DATA/orcl/datafile/undotbs1.264.882411811 YES  5

Example 2: Autoextend=on

SQL> alter database datafile '+DATA/orcl/datafile/undotbs1.264.882411811' autoextend on next 1M maxsize 1G;

Database altered.
`SQL> select tablespace_name, file_name,autoextensible, bytes/1024/1024 MB from dba_data_files where tablespace_name='UNDOTBS1';

TABLESPACE_NAME FILE_NAME                                  AUT  MB
--------------- ------------------------------------------ ---- ------
UNDOTBS1        +DATA/orcl/datafile/undotbs1.264.882411811 YES  7

1* select status, count(*) Num_Extents, sum(blocks) Num_Blocks, round((sum(bytes)/1024/1024),2) MB from dba_undo_extents group by status order by status

STATUS    NUM_EXTENTS 
--------- ----------- 
EXPIRED   54 
UNEXPIRED 29

No Active Extents are created.

SQL> select status, count(*) Num_Extents, sum(blocks) Num_Blocks, round((sum(bytes)/1024/1024),2) MB from dba_undo_extents group by status order by status

STATUS     NUM_EXTENTS
--------- ----------- 
ACTIVE     3 
EXPIRED    52 <--Expired extents were reused 
UNEXPIRED  28

STATUS     NUM_EXTENTS 
--------- ----------- 
ACTIVE     7 
EXPIRED    48 <--Expired extents were reused 
UNEXPIRED  28

STATUS     NUM_EXTENTS
--------- ----------- 
ACTIVE    11 
EXPIRED   38 <--Expired extents were reused 
UNEXPIRED 28

STATUS     NUM_EXTENTS 
--------- ----------- 
ACTIVE    19 
EXPIRED   34 <--Expired extents were reused 
UNEXPIRED 28

STATUS    NUM_EXTENTS 
--------- ----------- 
ACTIVE    23 
EXPIRED   30 <--Expired extents were reused 
UNEXPIRED 28

STATUS    NUM_EXTENTS 
--------- ----------- 
ACTIVE    27 
EXPIRED   20 <--Expired extents were reused 
UNEXPIRED 28

STATUS    NUM_EXTENTS 
--------- ----------- 
ACTIVE    36 
EXPIRED   10 <--Expired extents were reused 
UNEXPIRED 28

STATUS    NUM_EXTENTS 
--------- -----------
ACTIVE    40 
EXPIRED   11 <--Expired extents were reused 
UNEXPIRED 28

STATUS    NUM_EXTENTS 
--------- ----------- 
ACTIVE    45 
EXPIRED   9 <--Expired extents were reused ``
UNEXPIRED 28

检查数据文件size:

SQL> select tablespace_name, file_name,autoextensible, bytes/1024/1024 MB from dba_data_files where tablespace_name='UNDOTBS1'

TABLESPACE_NAME FILE_NAME                                  AUT MB
--------------- ------------------------------------------ --- ----------
UNDOTBS1        +DATA/orcl/datafile/undotbs1.264.882411811 YES 6

到目前为止,数据文件只调整了 1 次,增加了 1 MB

QL> select status, count(*) Num_Extents, sum(blocks) Num_Blocks, round((sum(bytes)/1024/1024),2) MB from dba_undo_extents group by status order by status

STATUS    NUM_EXTENTS
--------- ----------- 
ACTIVE    48 <--Datafile was autoextended and more free extents are available 
EXPIRED   8 
UNEXPIRED 28

STATUS    NUM_EXTENTS 
--------- ----------- 
ACTIVE    48 <--Datafile was autoextended and more free extents are available 
EXPIRED   8 
UNEXPIRED 28

STATUS    NUM_EXTENTS
--------- ----------- 
ACTIVE    48 <--Datafile was autoextended and more free extents are available 
EXPIRED   8 
UNEXPIRED 28

STATUS    NUM_EXTENTS 
--------- ----------- 
ACTIVE    48 <--Datafile was autoextended and more free extents are available 
EXPIRED   8 
UNEXPIRED 28

表空间将不断增加其大小,直到所有数据文件都已满。
查看新的数据文件大小:

SQL> select tablespace_name, file_name,autoextensible, bytes/1024/1024 MB from dba_data_files where tablespace_name='UNDOTBS1';

TABLESPACE_NAME FILE_NAME                                  AUT MB
--------------- ------------------------------------------ --- ----------
UNDOTBS1        +DATA/orcl/datafile/undotbs1.264.882411811 YES 11

为了知道undo表空间有多少次请求更多的空闲空间,有多少块被重用等等,可以查询视图 v$undostat。 此视图每 10 分钟显示一次统计信息:

SQL> select begin_time, 
UNXPSTEALCNT "#UnexpiredBlksTaken", 
EXPSTEALCNT "#ExpiredBlksTaken",
NOSPACEERRCNT "SpaceRequests"
from v$undostat order by begin_time; 2 3 4 5

BEGIN_TIME       #UnexpiredBlksTaken #ExpiredBlksTaken SpaceRequests
---------------- ------------------- ----------------- -------------
15-06-2015 02:24 6                   2                 6
15-06-2015 02:34 1                   0                 1
15-06-2015 02:44 11                  12                2
15-06-2015 02:54 76                  42                38
15-06-2015 03:04 71                  71                1
15-06-2015 03:14 0                   4                 0
15-06-2015 03:24 0                   10                0
15-06-2015 03:34 0                   0                 0
15-06-2015 03:44 0                   0                 0
9 rows selected.

为什么我们在这里看到很多在“15-06-2015 03:14”之前重用的未过期和过期块?这是因为我正在执行生成undo数据的更新,并且undo表空间已禁用自动扩展,因此它首先开始重用过期块,然后是未过期块。

为什么在“15-06-2015 03:14”和“15-06-2015 03:24”之间没有重用未过期的块,而只有过期的块?这是因为当时撤消表空间启用了自动扩展,但是(记住这一点)Oracle 在需要更多可用空间时不会立即自动扩展表空间,首先 Oracle 会查看过期块,并且只有在没有任何其他过期块时free 然后表空间被自动扩展(过期的范围最后被重用,直到所有的数据文件都已满并且它们不能被自动扩展更多)。

为什么在“15-06-2015 03:34”之后没有重复使用过期和未过期的块?这是因为所有可以重用的过期块已经被重用,并且表空间能够自动扩展,因此表空间不断变大。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值