您的位置:首页 > 其它

索引空间重用实验

2013-07-15 09:00 423 查看
随机删除:

SQL> create table TEST as select rownum id, object_name from dba_objects where rownum < 10;

Table created

SQL> create index idx_id_test on test(id);

Index created

SQL> analyze index idx_id_test validate structure;

Index analyzed

SQL> select * from index_stats;

HEIGHT BLOCKS NAME PARTITION_NAME LF_ROWS LF_BLKS LF_ROWS_LEN LF_BLK_LEN BR_ROWS BR_BLKS BR_ROWS_LEN BR_BLK_LEN DEL_LF_ROWS DEL_LF_ROWS_LEN DISTINCT_KEYS MOST_REPEATED_KEY BTREE_SPACE USED_SPACE
PCT_USED ROWS_PER_KEY BLKS_GETS_PER_ACCESS PRE_ROWS PRE_ROWS_LEN OPT_CMPR_COUNT OPT_CMPR_PCTSAVE

---------- ---------- ------------------------------ ------------------------------ ---------- ---------- ----------- ---------- ---------- ---------- ----------- ---------- ----------- --------------- ------------- ----------------- ----------- ----------
---------- ------------ -------------------- ---------- ------------ -------------- ----------------

1 8 IDX_ID_TEST 9 1 126 7996 0 0 0 0 0 0 9 1 7996 126
2 1 2 0 0 0 0

SQL> commit;

Commit complete

SQL> select lf_rows, del_lf_rows from index_stats;

LF_ROWS DEL_LF_ROWS

---------- -----------

9 0

SQL> DELETE FROM TEST WHERE ID IN (2,4,6,8);

4 rows deleted

SQL> analyze index idx_id_test validate structure;

Index analyzed

SQL> select lf_rows, del_lf_rows from index_stats;

LF_ROWS DEL_LF_ROWS

---------- -----------

9 4

SQL> col object_name format a30;

SQL> select object_name, object_id from dba_objects where object_name in ('IDX_ID_TEST');

OBJECT_NAME OBJECT_ID

------------------------------ ----------

IDX_ID_TEST 75626

SQL> alter session set events 'immediate trace name treedump level 75626';

Session altered

SQL>

SQL> SELECT T.VALUE || '/' || LOWER(RTRIM(I.INSTANCE, CHR(0))) || '_ora_' ||

2 P.SPID || '.trc' TRACE_FILE_NAME

3 FROM (SELECT P.SPID

4 FROM V$MYSTAT M, V$SESSION S, V$PROCESS P

5 WHERE M.STATISTIC# = 1

6 AND S.SID = M.SID

7 AND P.ADDR = S.PADDR) P,

8 (SELECT T.INSTANCE

9 FROM V$THREAD T, V$PARAMETER V

10 WHERE V.NAME = 'thread'

11 AND (V.VALUE = 0 OR T.THREAD# = TO_NUMBER(V.VALUE))) I,

12 (SELECT VALUE FROM V$PARAMETER WHERE NAME = 'user_dump_dest') T

13 ;

TRACE_FILE_NAME

--------------------------------------------------------------------------------

/u01/app/oracle/diag/rdbms/orcl/orcl/trace/orcl_ora_5544.trc

-----------------------------------------------------

vi /u01/app/oracle/diag/rdbms/orcl/orcl/trace/orcl_ora_5544.trc

*** 2013-07-10 17:36:02.241

----- begin tree dump

leaf: 0x41a289 4301449 (0: nrow: 9 rrow: 5)

----- end tree dump

--------------------------------------------------------------

SQL> select dbms_utility.data_block_address_file(4301449),dbms_utility.data_block_address_block(4301449) from dual;

DBMS_UTILITY.DATA_BLOCK_ADDRES DBMS_UTILITY.DATA_BLOCK_ADDRES

------------------------------ ------------------------------

1 107145

SQL> alter system dump datafile 1 block 107145;

System altered

-----------------------------------------------------------------------------

vi /u01/app/oracle/diag/rdbms/orcl/orcl/trace/orcl_ora_5544.trc

----------------------------------------------------------------------------

row#0[8020] flag: ------, lock: 0, len=12

col 0; len 2; (2): c1 02

col 1; len 6; (6): 00 41 a2 81 00 00

row#1[8008] flag: ---D--, lock: 2, len=12

col 0; len 2; (2): c1 03

col 1; len 6; (6): 00 41 a2 81 00 01

row#2[7996] flag: ------, lock: 0, len=12

col 0; len 2; (2): c1 04

col 1; len 6; (6): 00 41 a2 81 00 02

row#3[7984] flag: ---D--, lock: 2, len=12

col 0; len 2; (2): c1 05

col 1; len 6; (6): 00 41 a2 81 00 03

row#4[7972] flag: ------, lock: 0, len=12

col 0; len 2; (2): c1 06

col 1; len 6; (6): 00 41 a2 81 00 04

row#5[7960] flag: ---D--, lock: 2, len=12

col 0; len 2; (2): c1 07

col 1; len 6; (6): 00 41 a2 81 00 05

row#6[7948] flag: ------, lock: 0, len=12

col 0; len 2; (2): c1 08

col 1; len 6; (6): 00 41 a2 81 00 06

row#7[7936] flag: ---D--, lock: 2, len=12

col 0; len 2; (2): c1 09

col 1; len 6; (6): 00 41 a2 81 00 07

row#8[7924] flag: ------, lock: 0, len=12

col 0; len 2; (2): c1 0a

col 1; len 6; (6): 00 41 a2 81 00 08

----- end of leaf block dump -----

End dump data blocks tsn: 0 file#: 1 minblk 107145 maxblk 107145

SQL> insert into test values (10,'jerry');

1 row inserted

SQL> commit;

Commit complete

SQL> alter system checkpoint;

System altered

SQL> alter system dump datafile 1 block 107145;

System altered

-----------------------------------------------------------------------------

vi /u01/app/oracle/diag/rdbms/orcl/orcl/trace/orcl_ora_5544.trc

----------------------------------------------------------------------------

row#0[8020] flag: ------, lock: 0, len=12

col 0; len 2; (2): c1 02

col 1; len 6; (6): 00 41 a2 81 00 00

row#1[7996] flag: ------, lock: 0, len=12

col 0; len 2; (2): c1 04

col 1; len 6; (6): 00 41 a2 81 00 02

row#2[7972] flag: ------, lock: 0, len=12

col 0; len 2; (2): c1 06

col 1; len 6; (6): 00 41 a2 81 00 04

row#3[7948] flag: ------, lock: 0, len=12

col 0; len 2; (2): c1 08

col 1; len 6; (6): 00 41 a2 81 00 06

row#4[7924] flag: ------, lock: 0, len=12

col 0; len 2; (2): c1 0a

col 1; len 6; (6): 00 41 a2 81 00 08

row#5[7912] flag: ------, lock: 2, len=12

col 0; len 2; (2): c1 0b

col 1; len 6; (6): 00 41 a2 81 00 09

----- end of leaf block dump -----

End dump data blocks tsn: 0 file#: 1 minblk 107145 maxblk 107145

row#5是我们新插入的数据。空间被重用了。通过下面的SQL也可以验证。

SQL> analyze index idx_id_test validate structure;

Index analyzed

SQL> select lf_rows, del_lf_rows from index_stats;

LF_ROWS DEL_LF_ROWS

---------- -----------

6 0

总结:

1.任何一个新事务,往叶块中插入一条记录,ORACLE会自去移除/释放这个索引块内所有的已被删除的ENTRY;

2.在一个随机插入的索引块上,被删除的空间的重用往往不会存在什么问题,就像我们看到的一样,只有一有新插入,空间就会释放。

场景二、

一个表的字段是自增的,如果我们按照ID的某个范围,把记录删除,这些记录占用的索引空间能否释放。

SQL> drop table test;

Table dropped

SQL> create table TEST as select rownum id, object_name from dba_objects where rownum < 10000;

Table created

SQL> create index idx_id_test on test(id);

Index created

SQL> analyze index idx_id_test validate structure;

Index analyzed

SQL> select lf_rows, del_lf_rows from index_stats;

LF_ROWS DEL_LF_ROWS

---------- -----------

9999 0

SQL> delete from test;

9999 rows deleted

SQL> commit;

Commit complete

SQL> analyze index idx_id_test validate structure;

Index analyzed

SQL> select lf_blks,lf_rows, del_lf_rows from index_stats;

LF_BLKS LF_ROWS DEL_LF_ROWS

---------- ---------- -----------

21 9999 9999

SQL> insert into test select rownum + 20000,'jerry' from dba_objects where rownum <10000;

9999 rows inserted

SQL> commit;

Commit complete

SQL> analyze index idx_id_test validate structure;

Index analyzed

SQL> select lf_blks,lf_rows, del_lf_rows from index_stats;

LF_BLKS LF_ROWS DEL_LF_ROWS

---------- ---------- -----------

21 9999 0

场景二总结:

索引的叶块被清空后,会把这个叶块做为空闲块加入到索引段的BITMAP里面(如果使用的是ASSM),这样后面的事务就可以重新使用这些空闲的索引块了。需要指出的是,这些被清空的索引块虽然被加入到了索引的空间列表里面,但是他们依然在索引的逻辑结构中,被分支节点所参照(LINK),直到被重新使用,才会被重新RELINK.

场景三、

延迟块清除会在叶块做CLEANOUT,释放索引的空间

SQL> drop table test;

Table dropped

SQL> create table TEST as select rownum id, object_name from dba_objects where rownum < 10000;\

Table created

SQL> create index idx_id_test on test(id);

Index created

SQL> analyze index idx_id_test validate structure;

Index analyzed

SQL> select lf_rows, del_lf_rows from index_stats;

LF_ROWS DEL_LF_ROWS

---------- -----------

9999 0

SQL> select lf_blks,lf_rows, del_lf_rows from index_stats;

LF_BLKS LF_ROWS DEL_LF_ROWS

---------- ---------- -----------

21 9999 0

SQL> delete from test;

9999 rows deleted

不要提交,另开一个SESSION,执行SQL> alter system flush buffer_cache;回到原SESSION

SQL> commit;

Commit complete

SQL> ALTER SESSION SET EVENTS 'immediate trace name treedump level 75632';

Session altered

SQL>

SQL> SELECT T.VALUE || '/' || LOWER(RTRIM(I.INSTANCE, CHR(0))) || '_ora_' ||

2 P.SPID || '.trc' TRACE_FILE_NAME

3 FROM (SELECT P.SPID

4 FROM V$MYSTAT M, V$SESSION S, V$PROCESS P

5 WHERE M.STATISTIC# = 1

6 AND S.SID = M.SID

7 AND P.ADDR = S.PADDR) P,

8 (SELECT T.INSTANCE

9 FROM V$THREAD T, V$PARAMETER V

10 WHERE V.NAME = 'thread'

11 AND (V.VALUE = 0 OR T.THREAD# = TO_NUMBER(V.VALUE))) I,

12 (SELECT VALUE FROM V$PARAMETER WHERE NAME = 'user_dump_dest') T

13 ;

TRACE_FILE_NAME

--------------------------------------------------------------------------------

/u01/app/oracle/diag/rdbms/orcl/orcl/trace/orcl_ora_10752.trc

vi /u01/app/oracle/diag/rdbms/orcl/orcl/trace/orcl_ora_10752.trc

----- begin tree dump

*** 2013-07-10 18:09:55.297

branch: 0x41a2a9 4301481 (0: nrow: 21, level: 1)

leaf: 0x41a2aa 4301482 (-1: nrow: 485 rrow: 0)

leaf: 0x41a2ab 4301483 (0: nrow: 479 rrow: 0)

leaf: 0x41a2ac 4301484 (1: nrow: 479 rrow: 0)

leaf: 0x41a2ad 4301485 (2: nrow: 479 rrow: 0)

leaf: 0x41a2ae 4301486 (3: nrow: 479 rrow: 0)

leaf: 0x41a2af 4301487 (4: nrow: 478 rrow: 0)

leaf: 0x41a2b0 4301488 (5: nrow: 479 rrow: 0)

leaf: 0x41a2b1 4301489 (6: nrow: 479 rrow: 0)

leaf: 0x41a2b2 4301490 (7: nrow: 479 rrow: 0)

leaf: 0x41a2b3 4301491 (8: nrow: 478 rrow: 0)

leaf: 0x41a2b4 4301492 (9: nrow: 479 rrow: 0)

leaf: 0x41a2b5 4301493 (10: nrow: 479 rrow: 0)

leaf: 0x41a2b6 4301494 (11: nrow: 479 rrow: 0)

leaf: 0x41a2b7 4301495 (12: nrow: 479 rrow: 0)

leaf: 0x41a2b8 4301496 (13: nrow: 478 rrow: 0)

leaf: 0x41a2b9 4301497 (14: nrow: 479 rrow: 0)

leaf: 0x41a2ba 4301498 (15: nrow: 479 rrow: 0)

leaf: 0x41a2bb 4301499 (16: nrow: 479 rrow: 0)

leaf: 0x41a2bc 4301500 (17: nrow: 479 rrow: 0)

leaf: 0x41a2bd 4301501 (18: nrow: 478 rrow: 0)

leaf: 0x41a2be 4301502 (19: nrow: 417 rrow: 0)

----- end tree dump

SQL> select dbms_utility.data_block_address_file(4301502),dbms_utility.data_block_address_block(4301502) from dual;

DBMS_UTILITY.DATA_BLOCK_ADDRES DBMS_UTILITY.DATA_BLOCK_ADDRES

------------------------------ ------------------------------

1 107198

SQL> alter system dump datafile 1 block 107198;

System altered

vi /u01/app/oracle/diag/rdbms/orcl/orcl/trace/orcl_ora_10752.trc

Block header dump: 0x0041a2be

Object id on Block? Y

seg/obj: 0x12770 csc: 0x00.17ef89 itc: 2 flg: O typ: 2 - INDEX

fsl: 0 fnx: 0x41a2bd ver: 0x01

Itl Xid Uba Flag Lck Scn/Fsc

0x01 0x0000.000.00000000 0x00000000.0000.00 ---- 0 fsc 0x0000.00000000

0x02 0x000a.00a.00000329 0x00c00ccd.01c4.26 C-U- 0 scn 0x0000.0017eb81

Leaf block dump

===============

header address 9998940=0x98925c

kdxcolev 0

KDXCOLEV Flags = - - -

kdxcolok 0

kdxcoopc 0x80: opcode=0: iot flags=--- is converted=Y

kdxconco 2

kdxcosdc 0

kdxconro 0

kdxcofbo 36=0x24

kdxcofeo 8032=0x1f60

kdxcoavs 7996

kdxlespl 0

kdxlende 0

kdxlenxt 0=0x0

kdxleprv 4301501=0x41a2bd

kdxledsz 0

kdxlebksz 8032

*** dummy key ***

row#0[8019] flag: ---D--, lock: 0, len=13

col 0; len 3; (3): c2 60 54

col 1; len 6; (6): 00 41 a2 a5 00 12

----- end of leaf block dump -----

End dump data blocks tsn: 0 file#: 1 minblk 107198 maxblk 107198

场景三总结:

1.一些大的事务由于脏块较多,可以导致事务提交的时候,一些脏块已经被写入到磁盘了。

2.当没有清除的块再次被访问时,会发生延迟块清除。

3.延迟块清除会把这个块上所有的被删除的索引ENTRY做CLEANOUT.

在实验中,我们用到了ANALYZE XXX VALIDATE STRUCTURE, 在生产环境使用一定要小心,会在表上加一个类型为4的TM锁,阻塞表上的一切DML操作。如果用ONLINE做的话,在INDEX_STATS里面看不到记录。

上面符合的场景是,做的删除是随机的,所以很多索引叶块都存在被删除的ENTRY,如果这些块没有完全被清空,则不属于FREE块。

你后续插入的ID,如果都比现在的表的ID要大,则不会插入到之前的那些叶子节点里。

这个索引会一直向右延伸,从些变得不均衡,存在了很多的空洞,因此索引空间就是浪费的,这种情况要重建索引。

如果这些ID不是自增的,而是随机生成的,则这些空间早晚会被重用。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: