暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

全局索引_Oracle 12c 的延迟索引维护特性

wzf0072 2025-05-01
39

全局索引_Oracle 12c 的延迟索引维护特性

weixin_40007515

https://blog.csdn.net/weixin_40007515/article/details/112612162
在 Oracle 12c 中,有一个新特性被称为:延迟全局索引维护 - Delayed Global Index Maintenance 。

大家知道,在分区表中,如果创建全局索引,当我们对分区进行删除、截断等操作时,全局索引会失效,除非增加关键字 UPDATE GLOBAL INDEXES 同时维护索引,但是增加这个关键字又可能导致分区维护过慢。

在 12c 中,增加了一个特性,延迟全局索引维护,可以将索引维护工作异步延迟进行,在数据库中是通过 SYS.PMO_DEFERRED_GIDX_MAINT_JOB 任务,在每天02:00运行。

那么问题来了,延迟维护的全局索引,在查询中还会生效吗?

基于以上测试表创建一个全局索引:

SQL> create index enmotech_idx1 on enmotech (depid) global ;
Index created.
索引在查询中生效:


删除一个分区,再来检查索引状态,在 orphaned_entries 字段已经记录了索引出现孤儿条目:

SQL> alter table enmotech drop partition p2 update indexes;
Table altered.
SQL> COL INDEX_NAME FOR A20
SQL> select index_name, status,orphaned_entries
from dba_indexes
where index_name='ENMOTECH_IDX1';
INDEX_NAME STATUS ORP
-------------------- -------- ---
ENMOTECH_IDX1 VALID YES
注意此时的执行计划,仍然使用了索引,但是多了一个谓词过滤条件,是通过 TBL$OR$IDX$PART$NUM 函数对 ROWID 进行判断过滤,以保证索引中的孤儿条目不会被执行,当然有了这个步骤,我们看到递归调用的数量大大增加了:


我们可以检查一下 PMO_DEFERRED_GIDX_MAINT_JOB 的工作情况,其执行是调用了dbms_part的索引维护包:

SQL> exec print_table('select JOB_NAME,LAST_START_DATE,RUN_COUNT from dba_scheduler_jobs where job_name=''PMO_DEFERRED_GIDX_MAINT_JOB''');
JOB_NAME : PMO_DEFERRED_GIDX_MAINT_JOB
LAST_START_DATE : 11-JUL-18 02.00.00.356202 AM UTC
RUN_COUNT : 73
-----------------
SQL> select program_action
from dba_SCHEDULER_PROGRAMS
where program_name='PMO_DEFERRED_GIDX_MAINT'
/
PROGRAM_ACTION
------------------------------------------------------------
dbms_part.cleanup_gidx_internal(
noop_okay_in => 1);
现在手工调用,消除索引的孤儿状态,查询即刻恢复到正常的状态:

SQL> exec dbms_part.cleanup_gidx_internal(noop_okay_in => 1);
PL/SQL procedure successfully completed.
SQL> select index_name, status,orphaned_entries
from dba_indexes where index_name='ENMOTECH_IDX1';
INDEX_NAME STATUS ORP
-------------------- -------- ---
ENMOTECH_IDX1 VALID NO

TBL$OR$IDX$PART$NUM 的身世之谜

我们已经反复看到了 TBL$OR$IDX$PART$NUM 的身影,那么现在是时候研究一下这是一个什么函数了。

TBL$OR$IDX$PART$NUM 函数是一个内部函数,用于确定特定记录所属的分区。这个函数经常用于各种内部操作,前面我们已经见到了几个案例。
函数调用的基本格式如下:
TBL$OR$IDX$PART$NUM(PARTITIONED_TABLE_NAME,0,d#,p#,COLUMN_NAME) .
这个函数没有文档说明,需要通过测试来进行一些验证。如下创建测试分区表:

create table enmotech
( depid number,
kpiid varchar2(1),
ename varchar2(10),
npscr number)
partition by range (depid,kpiid)
subpartition by range (npscr)
subpartition template
( subpartition G1 values less than(60),
subpartition G2 values less than(90),
subpartition G3 values less than(100))
( partition "P1" values less than (10,'A'),
partition "P2" values less than (10,'B'),
partition "P3" values less than (10,'C'),
partition "P4" values less than (20,'A'),
partition "P5" values less than (20,'B'),
partition "P6" values less than (20,'C'));
insert into enmotech values(10, 'A','ANG', 95);
insert into enmotech values(10, 'B','ING', 85);
insert into enmotech values(10, 'C','ION', 75);
insert into enmotech values(20, 'A','HUA', 95);
insert into enmotech values(20, 'B','JUU', 85);
commit;
如果我们想找出 (depid,kpiid)为 (20,'B')的记录所属分区,以下查询即可支持:

select TBL$OR$IDX$PART$NUM("C##EYGLE"."ENMOTECH", 0, 1, 0, 20, 'B') pt
from dual;
PT
----------
6
查询一下表中现有记录及分区情况:

SQL> SELECT en.*,
TBL$OR$IDX$PART$NUM("C##EYGLE"."ENMOTECH", 0, 1, 0,
en."DEPID", en."KPIID") pt
FROM ENMOTECH en;
DEPID K ENAME NPSCR PT
---------- - ---------- ---------- ----------
10 A ANG 95 2
10 B ING 85 3
10 C ION 75 4
20 A HUA 95 5
20 B JUU 85 6
根据ROWID转换对象号出来:

SQL> select
tbl$or$idx$part$num("C##EYGLE"."ENMOTECH",
0,
4,
0,
"ROWID") objn from enmotech ;
OBJN
----------
96047
96048
96049
96050
96051
有了这个对象号,关联 DBA_OBJECTS 或者 USER_OBJECTS ,可以找到对象名称等信息,整个转换链路就可以非常灵活.

注意,以下查询是在 11.2.0.4 版本上的查询输出,我们可以清晰的看到每一条记录所属的对象和分区:


————————————————

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

原文链接:https://blog.csdn.net/weixin_40007515/article/details/112612162

「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论