Oracle 的LOB类型索引的转移,或是重建问题

Oracle 的LOB类型索引的转移,或是重建问题

原文地址:http://space.itpub.net/7728585/viewspace-683081

当我们想重建LOB类型的索引的时候,就会出现报错,重现如下:
create table test
 ( id int, txt clob );

SQL> select * from user_segments;
 
SEGMENT_NAME                                                                     PARTITION_NAME                 SEGMENT_TYPE       TABLESPACE_NAME          

         BYTES     BLOCKS    EXTENTS INITIAL_EXTENT NEXT_EXTENT MIN_EXTENTS MAX_EXTENTS PCT_INCREASE  FREELISTS FREELIST_GROUPS BUFFER_POOL
-------------------------------------------------------------------------------- ------------------------------ ------------------ -------------------------

----- ---------- ---------- ---------- -------------- ----------- ----------- ----------- ------------ ---------- --------------- -----------
TEST                                                                                                            TABLE              USERS                    

      41943040       5120         55          65536                       1  2147483645                                         DEFAULT
SYS_IL0000049476C00002$$                                                                                        LOBINDEX           USERS                    

         65536          8          1          65536                       1  2147483645                                         DEFAULT
SYS_LOB0000049476C00002$$                                                                                       LOBSEGMENT         USERS                    

         65536          8          1          65536                       1  2147483645                                         DEFAULT

alter index SYS_IL0000049476C00002$$ rebuild tablespace users ONLINE NOLOGGING
 
ORA-02327: 无法以数据类型 LOB 的表达式创建索引



我们先回忆一下相关知识,以下来自ORACLE 9I&10G编程艺术
  lobindex和lobsegment,它们做什么用?创建这些段是为了支持我们的LOB列。我们的实际LOB数据就存储在lobsegment中(确实,LOB数据也有可能存储在表T中,不过稍后讨论

ENABLE STORAGE IN ROW子句时还会更详细地说明这个内容)。lobindex用于执行LOB的导航,来找出其中的某些部分。创建一个LOB列时,一般来说,存储在行中的这是一个指针(

pointer),或LOB定位器(LOB locator)。我们的应用所获取的就是这个LOB定位器。当请求得到LOB的“12.000~2,000字节”时,将对lobindex使用LOB定位器来找出这些字节存

储在哪里,然后再访问lobsegment。可以用lobindex很容易地找到LOB的各个部分。由此说来,可以把LOB想成是一种主/明细关系。
  表中的LOB实际上只是指向lobindex,lobindex再指向LOB本身的各个部分。为了得到LOB中的N~M字节,要对表中的指针(LOB定位器)解除引用,遍历lobindex结构来找到所需的

数据库(chunk),然后按顺序访问。这使得随机访问LOB的任何部分都能同样迅速,你可以用同样快的速度得到LOB的最前面、中间或最后面的部分,因为无需再从头开始遍历LOB


  ORACLE也说:The LOB index is an internal structure that is strongly associated with the LOB storage. 也就是说不让直接重建
  但是我觉得可以明确INDEX是用来确定LOBSEGMENT的位置,如果经常对表中的行进行DML或者对大字段进行DML,我觉得重建还是用必要的。
既然是索引就要遵守索引的原则。大量的DML必然使索引的页节点越来越多,深度越来越大,但是其中包含了空闲空间。
  ORACLE METALINK 说 Use the ALTER TABLE ... MOVE command which will rebuild  the indexes ,也就是使用ALTER TABLE MOVE语句来进行REBUILD索引。
  下面就测试一下:
   首先理解几个概念,才能了解实验结果:
1、IN ROW 默认的这个子句是(ENABLE STORAGE IN ROW),也就是小于4000字节就存储在表段中,如果大于4000字节就存储在lob段中,同时使用LOBINDEX来指定位置,我这里使

用DISABLE STORAGE IN ROW,也就是不管多大都存在LOBSEGMENT中。
2、CHUNK 表示最小LOGSEGMENT最小的存储单元,而且一个CHUNK只限于一个SEGMENT行使用,如果一个CHUNK设置为32K,你的SEGMENT行只有2K那就要浪费30k。
3、CACHE 表示是否把读取写入LOGSEGMENT记录到缓存,默认是NOCACHE,可以是CACHE和CACHE READS,前者读写都保存,后者读保存,写是直接写。而NOCACHE,就是直接读写。

下面是我建立表的语句。
  CREATE TABLE "PPTEST"."TEST2"
   ( "ID" NUMBER(*,0),
 "TXT" CLOB
   ) PCTFREE 10 PCTUSED 40 INITRANS 1 MAXTRANS 255 NOCOMPRESS LOGGING
  STORAGE(INITIAL 65536 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645
  PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1 BUFFER_POOL DEFAULT)
  TABLESPACE "USERS"
 LOB ("TXT") STORE AS (
  TABLESPACE "USERS" DISABLE STORAGE IN ROW CHUNK 8192 PCTVERSION 10
  NOCACHE
  STORAGE(INITIAL 65536 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645
  PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1 BUFFER_POOL DEFAULT))
我这里DISABLE STORAGE IN ROW CHUNK 8192,CHUNK是8K。
现在我插入数据
SQL> insert into test2
  2  select * from test;
 
589824 rows inserted
 这里有58W多行,计算一下SEGMENTS占用空间。589824*8K=4.5G
查看一下:
select SEGMENT_NAME,SEGMENT_TYPE,BYTES/1024/1024/1024 gb,BLOCKS from user_segments;
SYS_IL0000049480C00002$$                                                         LOBINDEX           0.03027343       3968
SYS_LOB0000049480C00002$$                                                        LOBSEGMENT         4.54199218     595328
TEST2                                                                            TABLE              0.01855468       2432
确实我们的LOGSEGMENT是4.5G。
现在我们收集统计信息,并且对索引进行分析如下:
SQL> execute dbms_stats.gather_schema_stats(ownname => 'PPTEST',cascade => true);
 
PL/SQL procedure successfully completed
analyze index SYS_IL0000049480C00002$$ validate structure;
analyze index SYS_IL0000049480C00002$$ compute statistics;
过后查看都没有发现LOGINDEX的结构信息,不知道为何。
但是考虑进行了大量的DML够后进行REBULIDING索引的大小肯定会减少。
现在我们来进行REBULDING实验。
首先模拟大量删除插入,
delete  test2;
insert into test2
select id,txt from (select rownum rn, id, txt from test) where mod(rn, 8) = 0;
先全部删除,然后再插入1/8的数据。(过程巨慢)
SQL> delete  test2;
 
589824 rows deleted
查看
select SEGMENT_NAME,SEGMENT_TYPE,BYTES/1024/1024/1024 gb,BLOCKS from user_segments;
SYS_IL0000049480C00002$$                                                         LOBINDEX             0.078125      10240
SYS_LOB0000049480C00002$$                                                        LOBSEGMENT         4.60449218     603520
TEST2                                                                            TABLE              0.01855468       2432
索引的块大量增加,占用空间也大量增加,这里我也不太明白为何大量增加。这时其实没有任何数据了。
然后进行了插入。
SQL> insert into test2
  2  select id,txt from (select rownum rn, id, txt from test) where mod(rn, 8) = 0;
 
73728 rows inserted
 查看
select SEGMENT_NAME,SEGMENT_TYPE,BYTES/1024/1024/1024 gb,BLOCKS from user_segments;
SYS_IL0000049480C00002$$                                                         LOBINDEX            0.0859375      11264
SYS_LOB0000049480C00002$$                                                        LOBSEGMENT         5.10449218     669056
TEST2                                                                            TABLE              0.01855468       2432
 
其实这个时候数据只是以前的1/8 但是LOGSEGMENT和LOBINDEX 却更大。所以有大量的浪费空间。
我们直接重建TEST2表
SQL> alter table test2 move tablespace users;
查看
SYS_IL0000049480C00002$$                                                         LOBINDEX            0.0859375      11264
SYS_LOB0000049480C00002$$                                                        LOBSEGMENT         5.10449218     669056
TEST2                                                                            TABLE              0.00292968        384
只是重建了TEST2段

使用语句
  ALTER TABLE test2 MOVE
  TABLESPACE users
  LOB (TXT) STORE AS lobsegment
  (TABLESPACE users  );
进行重建
重建期间可以看到临时对象如下:
4.635                                                                            TEMPORARY          0.00061035         80
4.187                                                                            TEMPORARY           0.1328125      17408
4.611                                                                            TEMPORARY          0.00097656        128
显然表本身,LOBSEGMENT和LOBINDEX都再重建
然后查看
SQL> select SEGMENT_NAME,SEGMENT_TYPE,BYTES/1024/1024/1024 gb,BLOCKS from user_segments;
 
SEGMENT_NAME                                                                     SEGMENT_TYPE               GB     BLOCKS
-------------------------------------------------------------------------------- ------------------ ---------- ----------
TEST2                                                                            TABLE              0.00292968        384
LOBSEGMENT                                                                       LOBSEGMENT         0.56835937      74496
SYS_IL0000049480C00002$$                                                         LOBINDEX           0.00390625        512
因为我这里使用 lobsegment所以以前的SYS_LOB0000049480C00002$$ 变为了LOBSEGMENT,可以看到这个时候容量正常了。0.56G刚好是以前的1/8.

如果想单独重建会报错。METALINK上记录如下:
Explanation
-----------

The 'ALTER TABLE foo MODIFY LOB (lobcol) ...' syntax does not allow
for a change of tablespace

  ALTER TABLE  my_lob
   MODIFY LOB (a_lob)
   (TABLESPACE new_tbsp);

  (TABLESPACE new_tbsp)
   *
  ORA-22853: invalid LOB storage option specification

You have to use the MOVE keyword instead as shown in the examples.

 

结论:
1、LOGSEGMENT不会重用HWM以下的空间,所以大量DML会不断增加它的大小。
2、进行LOBsegment和LOBINDEX重建很有必要,使用语法如下:
  ALTER TABLE test2 MOVE
  TABLESPACE users
  LOB (TXT) STORE AS lobsegment
  (TABLESPACE users  );
必须和表一起重建,单独重建LOBSEGMENT或者LOGINDEX没有办法。

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/21907916/viewspace-713787/,如需转载,请注明出处,否则将追究法律责任。

转载于:http://blog.itpub.net/21907916/viewspace-713787/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值