索引rebuild與rebuild online區別 1.0目的,本篇文檔探討索引rebuild 與 rebuild online的區別 2.0猜測:已有的知識 2.1對索引rebuild重建會對錶申請TM4級表鎖,將會影響業務修改數據,而對索引進行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號鎖
--查詢申請分區的記錄
SYS@ENMO>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 sqlplus@enmo (TNS V1-V3) enq: TM - contention 1 58
1 58 593 HR HR 02ywzvmsk9ng4 enmo sqlplus@enmo (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鎖記錄
SYS@ENMO>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