数据库中的跳号问题真的需要管理吗?

在数据库中,我们经常为对象或记录赋予一个顺序增长的序号作为标记,序列就是实现数据库功能的特性之一。有了顺序号就有了一类烦恼:如何防止跳号?

最近,在Oracle 23ai 版本中测试时,通过一个报错遭遇到Oracle为解决跳号问题引入和内部特性。

outside_default.png

如下,在删除用户时遇到 ORA-01653 错误,不能扩展空间,引发空间扩展的对象是 OBJNUM_REUSE 。这是当删除对象时,数据库在 OBJNUM_REUSE 中增加记录,因空间不足而报错:

SQL> drop user c##eygle cascade;
drop user c##eygle cascade
*
ERROR at line 1:
ORA-00604: error occurred at recursive SQL level 1
ORA-01653: unable to extend table SYS.OBJNUM_REUSE by 128 in tablespace SYSTEM

此时数据库中共记录了15万个可以重用的对象号:

SQL> select count(*) from OBJNUM_REUSE;


  COUNT(*)
----------
    154500

问题原因很清楚,就是在删除用户时,触发了数据库的后台内部任务,级联引发空间扩展问题,从而出现了 ORA-01653 错误。

但是 SYS.OBJNUM_REUSE 是一个什么对象呢?

这是从Oracle 19c开始,增加的一个“对象号重用“的新特性,从而引入的数据库对象,objnum_reuse 是一个系统表,包含2个字段(记录了对象号和时间),还伴随创建了2个索引:

create table objnum_reuse (
  obj# number not null,
  ins_date date)
/
create unique index i_objnum_reuse1 on objnum_reuse(obj#)
/
create index i_objnum_reuse2 on objnum_reuse(ins_date, obj#)
/

为什么要重用对象号呢?

这是因为在Oracle RDBMS中有一些内部强加的限制,例如对象号在rowid中被引用(对象号占32bit),数据库中的对象号最多可以分配 4G 个。

outside_default.png

此限制会影响可以创建的对象数、可以对这些对象执行的DDL操作数以及可以创建的轻量级作业数。达到这个限制是灾难性的——数据库基本上变得不可用,因为无法创建新对象,无法在对象上运行DDL,也无法运行轻量级作业。如果数据库关闭,则可能无法重新打开。

对于极其繁忙的数据库、经常反复创建对象的数据库,就可能用完对象号。

在大约10年前,我遇到过一个案例,在SAP的系统中,由于大量的临时计算会频繁的创建和删除对象,导致对象号快速增长,在后续的DBMS_STATS任务调度上出现了问题。

outside_default.png

这是一个非常早期的数据库版本,叠加一些内部限制和序号保留,可用的用户对象号达不到理论数量。保留了当时的查询记录:

SQL> select count(0) from dba_objects where object_id > power(2,31);


  COUNT(0)
----------
   1174755

手工执行相关操作,都会遇到数值溢出的错误(还可能遇到ORA-600 [kkdlron-max-objid] 或 ORA-600 [15260]错误):

SQL> BEGIN
2  DBMS_AQADM.DROP_QUEUE_TABLE('Q_TABLE');
3  END;
4  /
BEGIN
*
ERROR at line 1:
ORA-01426: numeric overflow
ORA-06512: at "SYS.DBMS_AQADM_SYS", line 4310
ORA-06512: at "SYS.DBMS_AQADM", line 197
ORA-06512: at line 2

为了应对对象号浪费问题,现在Oracle 实现了自动的对象标识符回收方法,将丢弃对象的回收对象编号缓存在新的内部表中。当系统对象标识符达到用尽状态时,数据库会无缝地切换到使用缓存的值。还提供了一个存储过程,用于手动收集废弃的对象号填充内部表。

对象号重用,除了引入了以上描述的表和索引外,还包括:引入初始化隐含参数“_reuse_object_numbers”。

当此参数设置为“0”时,对象标识符回收将关闭。若要激活回收功能,需要将其设置为“5”(不应设置为任何其他值)。此参数在19c中默认为“0”,但在23ai中,它默认为“5”。

一旦激活,任何丢弃的对象(包括在安装和/或激活补丁之前创建的对象)的对象编号都将被回收。请注意,在这种情况下“已删除”意味着标识符已从SYS数据字典中删除,回收站中的项目并非如此(回收站中项目的编号需要Purge后才能回收)。

针对这个特性,还引入了存储过程 OBJNUM_REUSE_HOLES。数据库中增加了一个名为OBJNUM_REUSE_HOLES的新过程。此程序可用于手动填充SYS.OBJNUM_REUSE表,其中包含通过扫描SYS获得的对象标识符。OBJ$表中未使用的标识符或序列中当前未使用的“孔”。

PL/SQL过程已成功完成。
SQL>exec objnum_reuse_holes(100000)

注意,对于23ai之前的版本,必须显式激活特性。在数据库完全用完对象编号之前,可以随时设置“_reuse_object_numbers”参数。

当该特性被激活时,对象标识符重用实际上不会生效,直到常规限制用完为止。但是,一旦设置了“_reuse_object_numbers”=5,就会开始捕获丢弃的对象编号。

当达到对象标识符的最大限制并启用此特性时,系统将自动切换到从SYS表中获取对象标识符。OBJNUM_REUSE无缝连接,不会对应用程序造成任何中断或任何可见差异。

outside_default.png

Oracle的跳号治理,你觉得如何


云和恩墨大讲堂 | 一个分享交流的地方 

长按,识别二维码,加入万人交流社群

请备注:云和恩墨大讲堂

  点个“在看” 

你的喜欢会被看到❤

  • 5
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值