索引rebuild和rebuild online是运维环境中经常遇到的问题。但是无论哪种,大数据索引对象的rebuild都是消耗资源的大规模操作,都需要进行时间窗规划,避免对在线系统运行有影响。
本篇主要介绍对索引的另一种精简操作方法:coalesce合并。从之前的讨论我们已经知道,索引结构一般是一个不断“退化”的平衡结构,如果有一个新值加入,就可能会伴随叶子节点拓展,甚至包括分支节点创建。而一个值被删除修改,叶子节点只是被标注为已删除,不会进行节点合并和回收。这样,正常环境下的索引应该是叶子“支离破碎”、“缓慢膨胀”的段结构。
回收空间、让叶子节点更加紧密是管理员考虑rebuild的基本出发动机。紧密的新索引的确空间占用比较小,检索速度也较快。但是之后插入、更新、删除的过程后,依然伴随着空间分配过程的损耗。所以,笔者个人认为:也许健康的索引结构就应该是“支离破碎”、“缓慢膨胀”。Coalesce操作提供的一种逻辑重组索引的方式,仅对索引树进行重组,不进行数据回收。
1、环境介绍
笔者选择11gR2进行实验。
SQL> select * from v$version;
BANNER
--------------------------------------------------------------------------------
Oracle Database 11g Enterprise Edition Release 11.2.0.3.0 - 64bit Production
PL/SQL Release 11.2.0.3.0 - Production
CORE 11.2.0.3.0 Production
TNS for Linux: Version 11.2.0.3.0 - Production
NLSRTL Version 11.2.0.3.0 - Production
创建数据表T,构建索引。
SQL> create table t as select * from dba_objects ;
Table created
SQL> create index idx_t_id on t(object_id);
Index created
为了模拟效果,删除大部分数据构成死节点。
SQL> select max(object_id) from t;
MAX(OBJECT_ID)
--------------
164092
SQL> delete t where object_id<164092;
77405 rows deleted
SQL> commit;
Commit complete
重新收集统计量。
SQL> exec dbms_stats.gather_table_stats(user,'T',cascade => true);
PL/SQL procedure successfully completed
SQL> commit;
Commit complete
SQL> select count(*) from t;
COUNT(*)
----------
1
2、coalesce操作
Delete操作既不会回收数据段,也不会回收索引段。当前一行数据表T对应的段信息如下:
SQL> select EXTENT_ID, FILE_ID, BLOCK_ID, BYTES, BLOCKS from dba_extents where owner='SYS' and segment_name='T';
EXTENT_ID FILE_ID BLOCK_ID BYTES BLOCKS
---------- ---------- ---------- ---------- ----------
0 1 86984 65536 8
1 1 86992 65536 8
2 1 87000 65536 8
3 1 87008 65536 8
4 1 87016 65536 8
5 1 87024 65536 8
6 1 87032 65536 8
7 1 88960 65536 8
8 1 88968 65536 8
9 1 88976 65536 8
10 1 88984 65536 8
11 1 88992 65536 8
12 1 89000 65536 8
13 1 89008 65536 8
14 1 90360 65536 8
15 1 91008 65536 8
16 1 89088 1048576 128
17 1 89216 1048576 128
18 1 89344 1048576 128
19 1 89472 1048576 128
EXTENT_ID FILE_ID BLOCK_ID BYTES BLOCKS
---------- ---------- ---------- ---------- ----------
20 1 89600 1048576 128
21 1 89728 1048576 128
22 1 89856 1048576 128
23 1 89984 1048576 128
24 rows selected
索引段如下:
SQL> select EXTENT_ID, FILE_ID, BLOCK_ID, BYTES, BLOCKS from dba_extents where owner='SYS' and segment_name='IDX_T_ID';
EXTENT_ID FILE_ID BLOCK_ID BYTES BLOCKS
---------- ---------- ---------- ---------- ----------
0 1 91704 65536 8
1 1 91712 65536 8
2 1 91720 65536 8
3 1 91728 65536 8
4 1 91736 65536 8
5 1 91744 65536 8
6 1 91752 65536 8
7 1 91760 65536 8
8 1 91768 65536 8
9 1 92544 65536 8
10 1 92552 65536 8
11 1 92560 65536 8
12 1 92568 65536 8
13 1 92576 65536 8
14 1 92584 65536 8
15 1 92592 65536 8
16 1 91776 1048576 128
17 rows selected
多extent结构,表示结构没有回收。下面使用analyze语句分析一下索引的情况:
SQL> analyze index idx_t_id validate structure;
Index analyzed
SQL> select height, blocks, lf_rows, lf_blks, lf_rows_len, lf_blk_len, br_rows, br_blks, del_lf_rows from index_stats;
HEIGHT BLOCKS LF_ROWS LF_BLKS LF_ROWS_LEN LF_BLK_LEN BR_ROWS BR_BLKS DEL_LF_ROWS
---------- ---------- ---------- ---------- ----------- ---------- ---------- ---------- -----------