Eagle:
rebuild index为何要排序
我们都知道索引是有序的存储
然而在block内部,实际上索引键值的存储是无序的
比如说,你先存入了1,3
即使以后增加了一个2
那么在同一个数据块内部,数据库也不会去动1,3的存储
在读取的时候,oracle可以作简单的块内排序,进行有序的读取输出
在重建索引的时候
Oracle显然不会按照1,2,3..........的索引顺序来读出索引内容
因其代价高昂
Oracle实际执行的是Fast Full Scan
按顺序读取block
这样读取出来的数据需要重新sort
排序,然后重构索引
这个重构的索引在物理存储上比原来更为有序
总结:
1、索引的存储是,块内无序,块间有序
2、索引叶子节点内部没有存在 链表状结构来维护顺序,则row# 总是可能发生变化的。记录在块内物理上是无序的,但是在逻辑上通过row#来表达了顺序。
3、rebulid index 要考虑 rebuild后新的index大小,如果rebuild online 会有一些临时信息占用空间,这些都在index所在表空间上。另外,rebuild需要排序,一般sort area size是不够用的,会用到temp表空间。
4.如果是非ONLINE方式,通常会对该表设置一个表级共享(DML)锁,那么就对DML语句冲突,
如果设置ONLINE ,(会使用临时日志IOT表来记录中间改变的数据),但要使用两倍于传统方法的空间.表会变成行级共享锁,在创建索引或者ALTER完成后,对临时日志表与基表进行MERGE
注意并行处理,DDL,位图索引不能使用ONLINE。
5.从索引开始rebuild online开始的那一刻起,oracle会先创建一个SYS_JOURNAL_xxx的系统临时日志表,结构类似于mlog$_表,
通过内部触发器,记录了开始rebuild索引时表上所发生的改变的记录,当索引已经创建好之后,新数据将直接写入索引,
只需要把SYS_JOURNAL_xxx日志表中的改变维护到索引中即可。
6.rebuild index 是读取老的index的,但是 rebuild index online 是读取基表的。
我作了两个试验。
我的index大小为7M左右。
首先,我将index所在的tablespace只开到10M,临时表空间较大,
rebuild 时报无法在index所在的tablespace上扩展temp 段。
将表空间增大,rebuild成功。
在将临时表空间只开到5M,表空间开到20M,rebuild就报无法在temp表空间上扩展,将临时表空间增大到10M,rebuild成功
今天找了个时间做了把实验
SQL> select * from test_index;
ID NAME
--------------------------------------- --------------------
1 aa
2 aa
3 aa
35 aa
32 bb
SQL> select dump(id) from test_index;
DUMP(ID)
--------------------------------------------------------------------------------
Typ=2 Len=2: 193,2
Typ=2 Len=2: 193,3
Typ=2 Len=2: 193,4
Typ=2 Len=2: 193,36
Typ=2 Len=2: 193,33
SQL> alter system dump datafile 15 block 42 ;
*** 2004-04-05 11:49:19.947
Start dump data blocks tsn: 14 file#: 15 minblk 42 maxblk 42
buffer tsn: 14 rdba: 0x03c0002a (15/42)
scn: 0x0000.00196f9b seq: 0x01 flg: 0x00 tail: 0x6f9b0601
frmt: 0x02 chkval: 0x0000 type: 0x06=trans data
Block header dump: 0x03c0002a
Object id on Block? Y
seg/obj: 0x682f csc: 0x00.196f99 itc: 2 flg: - typ: 2 - INDEX
fsl: 0 fnx: 0x0 ver: 0x01
Itl Xid Uba Flag Lck Scn/Fsc
0x01 xid: 0x0000.000.00000000 uba: 0x00000000.0000.00 ---- 0 fsc 0x0000.00000000
0x02 xid: 0x0004.050.000002ed uba: 0x00000000.0000.00 ---- 0 fsc 0x0000.00000000
Leaf block dump
===============
header address 60386396=0x3996c5c
kdxcolev 0
kdxcolok 0
kdxcoopc 0x80: opcode=0: iot flags=--- is converted=Y
kdxconco 2
kdxcosdc 0
kdxconro 5
kdxcofbo 46=0x2e
kdxcofeo 7976=0x1f28
kdxcoavs 7930
kdxlespl 0
kdxlende 0
kdxlenxt 0=0x0
kdxleprv 0=0x0
kdxledsz 0
kdxlebksz 8036
row#0[8024] flag: -----, lock: 0
col 0; len 2; (2): c1 02
col 1; len 6; (6): 03 c0 00 0a 00 00
row#1[8012] flag: -----, lock: 0
col 0; len 2; (2): c1 03
col 1; len 6; (6): 03 c0 00 0a 00 01
row#2[8000] flag: -----, lock: 0
col 0; len 2; (2): c1 04
col 1; len 6; (6): 03 c0 00 0a 00 02
row#3[7988] flag: -----, lock: 0
col 0; len 2; (2): c1 21
col 1; len 6; (6): 03 c0 00 0a 00 04
row#4[7976] flag: -----, lock: 0
col 0; len 2; (2): c1 24
col 1; len 6; (6): 03 c0 00 0a 00 03
----- end of leaf block dump -----
SQL> insert into test_index values(21,'cs');
commit;
SQL> alter system dump datafile 15 block 42 ;
*** 2004-04-05 12:27:13.381
Start dump data blocks tsn: 14 file#: 15 minblk 42 maxblk 42
buffer tsn: 14 rdba: 0x03c0002a (15/42)
scn: 0x0000.00196f9f seq: 0x01 flg: 0x02 tail: 0x6f9f0601
frmt: 0x02 chkval: 0x0000 type: 0x06=trans data
Block header dump: 0x03c0002a
Object id on Block? Y
seg/obj: 0x682f csc: 0x00.196f99 itc: 2 flg: - typ: 2 - INDEX
fsl: 0 fnx: 0x0 ver: 0x01
Itl Xid Uba Flag Lck Scn/Fsc
0x01 xid: 0x0000.000.00000000 uba: 0x00000000.0000.00 ---- 0 fsc 0x0000.00000000
0x02 xid: 0x0005.04b.000002e3 uba: 0x00800815.0090.35 --U- 1 fsc 0x0000.00196f9f
Leaf block dump
===============
header address 60386396=0x3996c5c
kdxcolev 0
kdxcolok 0
kdxcoopc 0x80: opcode=0: iot flags=--- is converted=Y
kdxconco 2
kdxcosdc 0
kdxconro 6
kdxcofbo 48=0x30
kdxcofeo 7964=0x1f1c
kdxcoavs 7916
kdxlespl 0
kdxlende 0
kdxlenxt 0=0x0
kdxleprv 0=0x0
kdxledsz 0
kdxlebksz 8036
row#0[8024] flag: -----, lock: 0
col 0; len 2; (2): c1 02
col 1; len 6; (6): 03 c0 00 0a 00 00
row#1[8012] flag: -----, lock: 0
col 0; len 2; (2): c1 03
col 1; len 6; (6): 03 c0 00 0a 00 01
row#2[8000] flag: -----, lock: 0
col 0; len 2; (2): c1 04
col 1; len 6; (6): 03 c0 00 0a 00 02
row#3[7964] flag: -----, lock: 2
col 0; len 2; (2): c1 16
col 1; len 6; (6): 03 c0 00 0a 00 05
row#4[7988] flag: -----, lock: 0
col 0; len 2; (2): c1 21
col 1; len 6; (6): 03 c0 00 0a 00 04
row#5[7976] flag: -----, lock: 0
col 0; len 2; (2): c1 24
col 1; len 6; (6): 03 c0 00 0a 00 03
----- end of leaf block dump -----
End dump data blocks tsn: 14 file#: 15 minblk 42 maxblk 42
--------------------------------------------------------------------------------
Biti_rainy
如上红色部分,新记录的插入并没有导致物理位置发生变化。如果要维护块内顺序,则参考 在表数据块中是 row dictionary 有另外一个地方维护这个结构。但这在index dump中是看不出来这样的结构的,只能看到这里是根据顺序输出的trace。我曾经想过这样一个问题,那就是,如果要维护这个顺序,假如索引块中存在100个row记录,新插入一个记录进来(很显然这里每个row 消耗了12个字节,应该就是 rowid 6 , col length 1,col 2,lock 1,flag 1, row# 1), 这意味着新插入一条记录将可能修改很多记录的row#吗?
其实,如果能在变化中把索引block的二进制直接读出来观察变化应该可以立即断定。
很显然,索引叶子节点内部没有存在 链表状结构来维护顺序,则row# 总是可能发生变化的。记录在块内物理上是无序的,但是在逻辑上通过row#来表达了顺序。我们可以假想一种顺序读出数据的方式,block内部存在记录 kdxconro 条 ,则读出的时候建立结构数组 index_struc[kdxconro] ,当读到行号为 row# 的记录的时候就放入 index_struc[row#] 。 这样实现数据的有序读取, 当写入的时候,无论如何,可能去更改很多记录的 row# 了