索引rebuild与rebuild online区别

Posted lvcha001

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了索引rebuild与rebuild online区别相关的知识,希望对你有一定的参考价值。

索引rebuild与rebuild online区别

1.0目的,本篇文档探讨索引rebuild 与 rebuild online的区别

2.0猜测:已有的知识
2.1对索引rebuild重建会对表申请TM4级表锁,将会影响业务修改数据,而对索引进行rebuild online则不影响业务修改数据,但是可能会失败。
2.2对索引rebuild online,对于一个大的分区表,rebuild online速度非常慢,而rebuild速度对比很快
2.3对索引rebuild online查询数据库V$lOCK视图,发现对多个对象存在TM2、某个对象TM4级锁,但是不知道是什么对象

3.0实验思路
1.从锁角度查询区别
2.从执行计划查询区别
3.从10046分析查询区别(没整明白,可忽略)
申明,本次操作版本11.2.0.4

 

4.0测试看锁
创建一个分区表Local 索引,rebuild :rebuild online对比分析,得出结论
4.1 创建测试对象
SCOTT > create table t(id int,name varchar2(20)) partition by hash(id) partitions 4;
set timing on
declare
v_id int;
begin
for v_id in 1 .. 500000
loop
insert into t values(v_id,‘test‘||v_id);
end loop;
commit;
end;
/
Elapsed: 00:01:36.68
#drop index t_ind;
create index t_p_ind on t(id) local;

SCOTT > select a.TABLE_NAME,a.PARTITION_NAME,bytes/1024/1024 from user_tab_partitions a,dba_segments b where a.partition_name=b.PARTITION_NAME and a.table_name=‘T‘;
TABLE_NAME PARTITION_NAME BYTES/1024/1024
------------------ ------------------- ---------------
T SYS_P112 8
T SYS_P111 8
T SYS_P110 8
T SYS_P109 8
--查询重建索引SQL
SELECT ‘alter INDEX SCOTT.‘
|| index_name
|| ‘ REBUILD PARTITION ‘
|| PARTITION_NAME||‘;‘
FROM DBA_IND_PARTITIONS
where INDEX_OWNER=‘SCOTT‘ AND INDEX_NAME=‘T_P_IND‘;
‘ALTERINDEXSCOTT.‘||INDEX_NAME||‘REBUILDPARTITION‘||PARTITION_NAME||‘;‘
----------------------------------------------------------------------
alter INDEX SCOTT.T_P_IND REBUILD PARTITION SYS_P113;
alter INDEX SCOTT.T_P_IND REBUILD PARTITION SYS_P114;
alter INDEX SCOTT.T_P_IND REBUILD PARTITION SYS_P115;
alter INDEX SCOTT.T_P_IND REBUILD PARTITION SYS_P116;

test1
#drop table test1 purge;
create table t1 as select * from t;
SCOTT > select a.TABLE_NAME,segment_name,bytes/1024/1024 from user_tables a,dba_segments b where a.TABLE_NAME=b.segment_name and a.table_name=‘T1‘ and owner=‘SCOTT‘;
TABLE_NAME SEGMENT_NAME BYTES/1024/1024
------------------------------ -------------------------- ---------------
T1 T1 12

create index t_ind on t1(id);

 


4.2 分区表,rebuild看锁

--会话一、delete操作
SCOTT > delete t where id=1;
1 row deleted.
--会话二、rebuild
HR > alter session set ddl_lock_timeout=60000;
alter INDEX SCOTT.T_P_IND REBUILD PARTITION SYS_P113;
alter INDEX SCOTT.T_P_IND REBUILD PARTITION SYS_P114;
alter INDEX SCOTT.T_P_IND REBUILD PARTITION SYS_P115;
--执行上述三个分区索引rebuild都不存在问题,可以rebuild OK
HR > alter INDEX SCOTT.T_P_IND REBUILD PARTITION SYS_P116;


--会话hang住

--select v$lOCK

select * from
(select s.sid,l.type,id1,lmode,request,username,event,sql_id from v$lock l,v$session s where l.sid=s.sid and l.type in(‘TX‘,‘TM‘)) a left join
(select owner,object_name,object_type,object_id from dba_objects)b on a.id1=b.object_id order by 1;
SID TY ID1 LMODE REQUEST USERNAME EVENT SQL_ID OWNER OBJECT OBJECT_TYPE OBJECT_ID
----- -- ------ ----- ------- -------- ---------------------------- ------------- -------- ------- ----------------------------
58 TM 91888 2 0 HR enq: TM - contention 02ywzvmsk9ng4 SCOTT T TABLE 91888
58 TM 91892 0 4 HR enq: TM - contention 02ywzvmsk9ng4 SCOTT T TABLE PARTITION 91892
64 TX 131087 6 0 SCOTT SQL*Net message from client
64 TM 91892 3 0 SCOTT SQL*Net message from client SCOTT T TABLE PARTITION 91892
64 TM 91888 3 0 SCOTT SQL*Net message from client SCOTT T TABLE 91888
6 rows selected.
rebuild local index申请表分区TM4号锁,申请表TM2号锁
--查询申请分区的记录
[email protected]>select OWNER,OBJECT_NAME,SUBOBJECT_NAME,OBJECT_ID,OBJECT_TYPE from dba_objects where owner=‘SCOTT‘ and object_name=‘T‘;

OWNER OBJECT_NAME SUBOBJECT_NAME OBJECT_ID OBJECT_TYPE
-------- -------------- -------------------- ---------- -------------------
SCOTT T 91888 TABLE
SCOTT T SYS_P109 91889 TABLE PARTITION
SCOTT T SYS_P110 91890 TABLE PARTITION
SCOTT T SYS_P111 91891 TABLE PARTITION
SCOTT T SYS_P112 91892 TABLE PARTITION --


--会话三、delete操作
SYS>delete scott.t where id=300000;--hang住

--dml操作被rebuild会话锁住
SYS > select INST_ID II,sid,serial#,username,schemaname,sql_id,machine,program,EVENT,BLOCKING_INSTANCE BI,BLOCKING_SESSION BS from gv$session where blocking_session is not null order by BLOCKING_SESSION;
II SID SERIAL# USERNAME SCHEMANAME SQL_ID MACHINE PROGRAM EVENT BI BS
-- -------------- --------- ----------- ------------- --------- ------------------------- -------------------- --- ------
1 41 2469 SYS SYS g4022z4dskb8s enmo [email protected] (TNS V1-V3) enq: TM - contention 1 58
1 58 593 HR HR 02ywzvmsk9ng4 enmo [email protected] (TNS V1-V3) enq: TM - contention 1 64

--因此,直接对索引进行rebuild,重建过程中导致业务无法对分区表的该分区字段进行dml操作[

--疑问? 为何会话3,执行delete操作会Hang住,因为该数据存储在索引rebuild分区上,索引申请该分区TM4号锁,堵塞了dml申请TM3号锁,如果确定?
查询BLOCL_ID
select id,rowid,
dbms_rowid.rowid_object(rowid) object#,
dbms_rowid.rowid_relative_fno(rowid) file#,
dbms_rowid.rowid_block_number(rowid) block#,
dbms_rowid.rowid_row_number(rowid) row# from scott.t where id in(1,300000);
ID ROWID OBJECT# FILE# BLOCK# ROW#
---------- ------------------ ---------- ---------- ---------- ----------
1 AAAWb0AAEAACvPCAAp 91892 4 717762 41
300000 AAAWb0AAEAACvN8AAw 91892 4 717692 48

select
t.segment_name,
t.partition_name,
t.BLOCK_ID,(t.BLOCKS + t.BLOCK_ID -1) "MAX_BLOCK_ID"
from sys.dba_extents t,dba_tab_partitions p
where t.PARTITION_NAME=p.partition_name and p.TABLE_OWNER=‘SCOTT‘ and p.table_name=‘T‘;
SEGMENT_NA PARTITION_NAME BLOCK_ID MAX_BLOCK_ID
---------- ------------------------------ ---------- ------------
T SYS_P109 714368 715391
T SYS_P110 715392 716415
T SYS_P111 716416 717439
T SYS_P112 717440 718463 --717692--717762
--无法通过视图中查询索引记录的rowid信息,可以通过索引申请object_id,通过被阻塞的rowid找到对应Block_id与之对应的partition name



4.3 分区表,rebuild online看锁

--会话一、delete操作
SCOTT > delete t where id=1;
1 row deleted.
--会话二、rebuild
SYS > alter session set ddl_lock_timeout=60000;
SYS > alter INDEX SCOTT.T_P_IND REBUILD PARTITION SYS_P116 online;

--会话hang住

--select v$lOCK

select * from
(select s.sid,l.type,id1,lmode,request,username,event,sql_id from v$lock l,v$session s where l.sid=s.sid and l.type in(‘TX‘,‘TM‘)) a left join
(select owner,object_name,object_type,object_id from dba_objects)b on a.id1=b.object_id order by 1;

SID TY ID1 LMODE REQUEST USERNAME EVENT SQL_ID OWNER OBJECT_NAME OBJECT_TYPE OBJECT_ID
---- -- ---------- ----- ------- -------- ------------------------------ ------------- -------- -------------- --------------------------
41 TM 91888 2 0 SYS enq: TX - row lock contention 821crb119wpc6 SCOTT T TABLE 91888
41 TX 131074 0 4 SYS enq: TX - row lock contention 821crb119wpc6
41 TM 91926 4 0 SYS enq: TX - row lock contention 821crb119wpc6 SCOTT SYS_JOURNAL_91897 TABLE 91926
41 TM 91892 2 0 SYS enq: TX - row lock contention 821crb119wpc6 SCOTT T TABLE PARTITION 91892
41 TX 393227 6 0 SYS enq: TX - row lock contention 821crb119wpc6
58 TM 91888 3 0 SCOTT SQL*Net message from client SCOTT T TABLE 91888
58 TX 131074 6 0 SCOTT SQL*Net message from client
58 TM 91892 3 0 SCOTT SQL*Net message from client SCOTT T TABLE PARTITION 91892

8 rows selected.


--rebuild online 查询申请TM锁记录
[email protected]>select OWNER,OBJECT_NAME,SUBOBJECT_NAME,OBJECT_ID,OBJECT_TYPE from dba_objects where owner=‘SCOTT‘ and object_name=‘T‘;
OWNER OBJECT_NAME SUBOBJECT_NAME OBJECT_ID OBJECT_TYPE
-------- -------------- ------------------------------ ---------- -------------------
SCOTT T 91888 TABLE --rebuild online申请表TM2级锁
SCOTT T SYS_P109 91889 TABLE PARTITION
SCOTT T SYS_P110 91890 TABLE PARTITION
SCOTT T SYS_P111 91891 TABLE PARTITION
SCOTT T SYS_P112 91892 TABLE PARTITION --rebuild online申请、分区对象施加TM2号锁

--疑问?
rebuild 申请了一个91926 TM 4号锁,SCOTT SYS_JOURNAL_91897 TABLE
SCOTT > select * from SYS_JOURNAL_91897;
no rows selected
SCOTT > desc SYS_JOURNAL_91897
Name Null? Type
------------- -------- ---------------
C0 NOT NULL NUMBER(38)
OPCODE CHAR(1)
PARTNO NUMBER
RID NOT NULL ROWID


4.4 测试查询rebuild online期间系统自动创建的测试表记录的信息
测试对索引rebuild online分区进行delete/update/insert操作,查询临时表记录信息
--会话三、delete操作
SYS > delete scott.t where id=300000;
1 row deleted.
select * from SYS_JOURNAL_91897

C0 O PARTNO RID
---------- - ---------- ------------------------------
300000 D 3 D/////AAEAACvN8AAw --允许操作

--查询分区最大的id值
select max(id) from t partition(SYS_P112);
MAX(ID)
----------
499989

--update 非分区列,发现临时表不记录信息
update t set NAME=‘NAME2‘ where id=499989;

SCOTT > select * from SYS_JOURNAL_91897;

C0 O PARTNO RID
---------- - ---------- ------------------------------
300000 D 3 D/////AAEAACvN8AAw
--update 其它列,并不记录在此视图中

--update 索引列,发现还需要找到一个值,Update后还存在该表中,暂缓update操作测试
update t set id=id+400 where id=499989
*
ERROR at line 1:
ORA-14402: updating partition key column would cause a partition change

 

--由于insert 随机,因此插入四条记录进行测试
SCOTT > select * from SYS_JOURNAL_91897;

C0 O PARTNO RID
---------- - ---------- ------------------------------
300000 D 3 D/////AAEAACvN8AAw
declare
v_id int;
begin
for v_id in 500001 .. 500004
loop
insert into t values(v_id,‘test‘||v_id);
end loop;
commit;
end;
/
SCOTT > select max(id) from t partition(SYS_P112);
MAX(ID)
----------
500002
SCOTT > select * from SYS_JOURNAL_91897;

C0 O PARTNO RID
---------- - ---------- ------------------------------
300000 D 3 D/////AAEAACvN8AAw
500002 I 3 D/////AAEAACvPiAAA 可以看到Insert操作本行记录

--对insert记录进行delete,随后修改之前的记录,为insert记录,保证了在一个分区
delete t where id=500002;
update t set id=500002 where id=499989;
--再次查询视图记录
SCOTT > select * from SYS_JOURNAL_91897;

C0 O PARTNO RID
---------- - ---------- ------------------------------
300000 D 3 D/////AAEAACvN8AAw
500002 D 3 D/////AAEAACvPiAAA--之前记录的insert直接转换为delete记录,对一行记录,最后一次变更操作
499989 D 3 D/////AAEAACvPCAAo
500002 I 3 D/////AAEAACvPCAAo --非常有意思,这里记录一条update,直接转换为一条delete 一条Insert



--本次实验可以得到如下结论: 1.rebuild 操作会对分区对象添加TM4号锁,导致该分区对象无法dml操作影响业务
2.rebuild online则不会影响业务对分区字段dml操作,内部通过临时表记录修改信息,索引重建自动维护(rebuild期间修改的数据)

5.0 表索引,rebuild看执行计划
SYS > set autotrace on
delete scott.t where id=1;
alter INDEX SCOTT.T_P_IND REBUILD PARTITION SYS_P116;
SYS > select * from table(dbms_xplan.display_cursor(null,null,‘allstats last‘));
--通过种种SQL_ID找执行计划,均失败
--通过dbms 根据统计信息,模拟执行计划输出!


5.1 rebuild 分区表、分区索引
explain plan for
alter INDEX SCOTT.T_P_IND REBUILD PARTITION SYS_P116;
select * from table(dbms_xplan.display);

Plan hash value: 451004126

---------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | Pstart| Pstop |
---------------------------------------------------------------------------------------------------
| 0 | ALTER INDEX STATEMENT | | 124K| 609K| 102 (1)| 00:00:02 | | |
| 1 | INDEX BUILD NON UNIQUE | T_P_IND | | | | | | |
| 2 | SORT CREATE INDEX | | 124K| 609K| | | | |
| 3 | PARTITION HASH SINGLE| | | | | | 4 | 4 |
| 4 | INDEX FAST FULL SCAN| T_P_IND | | | | | 4 | 4 |
---------------------------------------------------------------------------------------------------
可以发现,对于分区表,rebuild索引,通过索引范围全扫描,扫描整个分区
索引快速全扫描->单分区全扫描->创建索引,需要排序->索引创建,非唯一->创建索引语句成功执行


5.2 rebuild online分区表、分区索引
explain plan for
alter INDEX SCOTT.T_P_IND REBUILD PARTITION SYS_P116 online;
select * from table(dbms_xplan.display);
---------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | Pstart| Pstop |
---------------------------------------------------------------------------------------------------
| 0 | ALTER INDEX STATEMENT | | 124K| 609K| 102 (1)| 00:00:02 | | |
| 1 | INDEX BUILD NON UNIQUE | T_P_IND | | | | | | |
| 2 | SORT CREATE INDEX | | 124K| 609K| | | | |
| 3 | PARTITION HASH SINGLE| | 124K| 609K| 102 (1)| 00:00:02 | 4 | 4 |
| 4 | TABLE ACCESS FULL | T | 124K| 609K| 102 (1)| 00:00:02 | 4 | 4 |
---------------------------------------------------------------------------------------------------
可以发现,对于分区表,rebuild online索引,进行的是全表扫描,随后分区扫描,
全表扫描->单分区扫描->

5.1/ 5.2对比,可以理解实际操作,rebuild online为什么一个多小时,rebuild 几分钟,全表扫描,数据量大差异越大

5.3rebuild 普通堆表、Global索引
explain plan for
alter index scott.t_ind rebuild;
select * from table(dbms_xplan.display);
--------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------------
| 0 | ALTER INDEX STATEMENT | | 500K| 2441K| 402 (1)| 00:00:05 |
| 1 | INDEX BUILD NON UNIQUE| T_IND | | | | |
| 2 | SORT CREATE INDEX | | 500K| 2441K| | |
| 3 | INDEX FAST FULL SCAN| T_IND | | | | |
--------------------------------------------------------------------------------

explain plan for
alter index scott.t_ind rebuild online;
select * from table(dbms_xplan.display);
--------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------------
| 0 | ALTER INDEX STATEMENT | | 500K| 2441K| 402 (1)| 00:00:05 |
| 1 | INDEX BUILD NON UNIQUE| T_IND | | | | |
| 2 | SORT CREATE INDEX | | 500K| 2441K| | |
| 3 | TABLE ACCESS FULL | T1 | 500K| 2441K| 402 (1)| 00:00:05 |
--------------------------------------------------------------------------------

对于普通表,全局索引而言,完全可以采用rebuild online操作,因为执行计划只有一条路!效率无明显差异


5.4rebuild 分区表、Global索引、Global索引 online对比
#drop index scott.t_p_ind;
#create index t_p_ind on t(id) local;
#create index scott.t_p_ind on scott.t(id);

explain plan for
alter index scott.t_p_ind rebuild;
select * from table(dbms_xplan.display);
----------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------------
| 0 | ALTER INDEX STATEMENT | | 500K| 2441K| 400 (1)| 00:00:05 |
| 1 | INDEX BUILD NON UNIQUE| T_P_IND | | | | |
| 2 | SORT CREATE INDEX | | 500K| 2441K| | |
| 3 | INDEX FAST FULL SCAN| T_P_IND | | | | |
----------------------------------------------------------------------------------

explain plan for
alter index scott.t_p_ind rebuild online;
select * from table(dbms_xplan.display);
--------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | Pstart| Pstop |
--------------------------------------------------------------------------------------------------
| 0 | ALTER INDEX STATEMENT | | 500K| 2441K| 400 (1)| 00:00:05 | | |
| 1 | INDEX BUILD NON UNIQUE| T_P_IND | | | | | | |
| 2 | SORT CREATE INDEX | | 500K| 2441K| | | | |
| 3 | PARTITION HASH ALL | | 500K| 2441K| 400 (1)| 00:00:05 | 1 | 4 |
| 4 | TABLE ACCESS FULL | T | 500K| 2441K| 400 (1)| 00:00:05 | 1 | 4 |
--------------------------------------------------------------------------------------------------
分区表,全局索引rebuild online操作时,会对所有分区hash查询 ,此处未明显判断是否有影响,暂存

 

结论,在对大的分区表索引进行重建,可以先尝试使用rebuild 而不加online,除非业务确实繁忙,其它场景可直接使用rebuild online 重建即可

 


6.0 使用10046 进行分区索引的重建
使用分区索引rebuild
分区索引rebuild online

#drop index scott.t_p_ind;
#create index scott.t_p_ind on scott.t(id) local;
查询分区表、分区段、块ID
select
t.segment_name,
t.partition_name,
t.BLOCK_ID,(t.BLOCKS + t.BLOCK_ID -1) "MAX_BLOCK_ID"
from sys.dba_extents t,dba_tab_partitions p
where t.PARTITION_NAME=p.partition_name and p.TABLE_OWNER=‘SCOTT‘ and p.table_name=‘T‘;
SEGMENT_NA PARTITION_NAME BLOCK_ID MAX_BLOCK_ID
---------- ------------------------------ ---------- ------------
T SYS_P109 714368 715391
T SYS_P110 715392 716415
T SYS_P111 716416 717439
T SYS_P112 717440 718463

查询分区索引、分区索引段
select index_name,s.partition_name,SEGMENT_NAME,HEADER_FILE,HEADER_BLOCK,HEADER_BLOCK+BLOCKS-1 "MAX_BLOCK" from dba_segments s,user_ind_partitions p where p.PARTITION_NAME=s.PARTITION_NAME and p.INDEX_NAME=‘T_P_IND‘;

INDEX_NAME PARTITION_ SEGMENT_NA HEADER_FILE HEADER_BLOCK MAX_BLOCK
---------- ---------- ---------- ----------- ------------ ----------
T_P_IND SYS_P124 T_P_IND 4 722962 723345
T_P_IND SYS_P123 T_P_IND 4 686610 686993
T_P_IND SYS_P122 T_P_IND 4 725266 725649
T_P_IND SYS_P121 T_P_IND 4 154 537


alter session set events ‘10046 trace name context forever, level 12‘;
alter index t_p_ind rebuild partition SYS_P121;
exit

找出部分记录进行注释说明,不能确保正确,仅限个人理解
--第一部分,SQL语句的执行,获取数据字典表信息,执行计划生成 !!!没看明白,暂时放弃
select u.name, o.name, o.namespace, o.type#, decode(bitand(i.property,1024),0,0,1), o.obj# from ind$ i,obj$ o,user$ u where i.obj#=:1 and o.obj#=i.bo# and o.owner#=u.user#
FETCH
STATNESTED LOOPS
STATNESTED LOOPS
STAT‘TABLE ACCESS BY INDEX ROWID IND$
STAT‘INDEX UNIQUE SCAN I_IND1
STAT‘TABLE ACCESS BY INDEX ROWID OBJ$ alter session set events ‘10046 trace name context forever, level 12‘;
STAT‘INDEX RANGE SCAN I_OBJ1 alter index object_idx rebuild online;
STAT‘TABLE ACCESS CLUSTER USER$
STAT‘INDEX UNIQUE SCAN I_USER#


alter session set events ‘10046 trace name context forever, level 12‘;
alter index t_p_ind rebuild partition SYS_P121 online;
exit

!!暂且放弃10046













































































































































































































































































































































以上是关于索引rebuild与rebuild online区别的主要内容,如果未能解决你的问题,请参考以下文章

Oracle的online index rebuild

Oracle的online index rebuild

(Oracle 11g)批量生成move表及rebuild索引语句

MySQL5.6 Online DDL 是否锁表rebuild表inplace的说明

索引 Reorganize 和 Rebuild 的区别

Oracle索引批量重置笔记