近日,新接手了一个数据库。检查某系统的时候发现,部分数据表存储在USERS表空间下了。
我们需要整理数据库对象至相对应的业务表空间中去
以下几个数据库对象在users表空间中:
select segment_name , segment_type , owner from dba_segments where TABLESPACE_NAME='USERS' AND OWNER='&OWNER_NAME';
SQL> select segment_name , segment_type , owner from dba_segments where TABLESPACE_NAME='USERS' AND OWNER='&OWNER_NAME';
Enter value for owner_name: IVYDD
old 1: select segment_name , segment_type , owner from dba_segments where TABLESPACE_NAME='USERS' AND OWNER='&OWNER_NAME'
new 1: select segment_name , segment_type , owner from dba_segments where TABLESPACE_NAME='USERS' AND OWNER='IVYDD'
SEGMENT_NAME SEGMENT_TYPE OWNER
-------------------------------------------- ------------------ -----------------------------
IVY_TEST TABLE IVYDD
EVAL_CONTACT TABLE IVYDD
SYS_IL0000089558C00006 LOBINDEX IVYDD
SYS_LOB0000089558C00006 LOBSEGMENT IVYDD
* 由于编辑器显示$字符异常,特此说明,segments_name 名称后都带有两个$$,文章下面将会省略这两个字符
- 发现USERS表空间下有两个LOB类型文件。
- 并且无法看出lob类型的segment所对应的表名。
说明:
对Oracle lob类型数据表而言,一个带lob列的数据表创建是要对应多个数据段创建的。除了传统的数据表创建的数据段Table Data Segment之外,一个lob列都会生成两个专门的段:lob段 和 lob索引段。
- Lob段(LobSegment)对应的是存放在数据表lob列上的数据。在Oracle的lob类型数据列,有两种保存位置结构。一个是in-row storage,也就是每一行的lob数据同其他列的数据以行的形式一起保存在数据块中。这种情况的lob列取值较小。而另一种为out-of-row storage,当lob对象较大,不能保存在一个数据块中时,可以将其放置在一个独立lobsegment中进行保存。而out-of-row storage时数据行中lob列上保存的只是一个指向lobsegment对应位置的指针引用。
- Lob索引段(LobIndex)是Oracle为每一个lob类型列强制生成的索引,主要作用是用于进行lob类型数据检索加速的操作。Lobindex与lob列共生,如果强制进行删除操作,是会报错的。
查看lob所对应的表名,以及该表上那个字段为lob类型:
col COLUMN_NAME for a20
SELECT owner , table_name , COLUMN_NAME , SEGMENT_NAME , TABLESPACE_NAME , INDEX_NAME FROM DBA_LOBS WHERE OWNER='IVYDD' AND SEGMENT_NAME like 'SYS_LOB0000089%';
OWNER TABLE_NAME COLUMN_NAME SEGMENT_NAME TABLESPACE_NAME INDEX_NAME
------------------------------ ------------------------------ -------------------- ------------------------------ ------------------------------ ------------------------------
IVYDD EVAL_CONTACT CONTEXT SYS_LOB0000089558C00006 USERS SYS_IL0000089558C00006
以上我们可以确定那两个LOB是属于:
- 数据表: IVYDD.EVAL_CONTACT
- LOB字段:CONTEXT
通常我们需要移动表至另一个表空间时,最常用的命令方法是使用move进行对象移动。
SQL> select segment_name, segment_type, tablespace_name from user_segments;
SEGMENT_NAME SEGMENT_TY TABLESPACE_NAME
------------------------------ ---------- ------------------------------
EVAL_CONTACT TABLE USERS
SYS_LOB0000089558C00006 LOBSEGMENT USERS
SYS_IL0000089558C00006 LOBINDEX USERS
3 rows selected
SQL> alter table t move tablespace tbs_ivy;
Table altered
SQL> select segment_name, segment_type, tablespace_name from user_segments;
SEGMENT_NAME SEGMENT_TY TABLESPACE_NAME
------------------------------ ---------- ------------------------------
EVAL_CONTACT TABLE TBS_IVY
SYS_LOB0000089558C00006 LOBSEGMENT USERS
SYS_IL0000089558C00006 LOBINDEX USERS
SQL> alter index SYS_IL0000089558C00006 rebuild tablespace TBS_IVY;
ORA-02327: 无法以数据类型 LOB 的表达式创建索引
- 可以看到用我们常用的move方法进行无法移动LOB对象的。
- 并且也不能使用rebuild方法对LOB INDEX进行重建。
那么我们应该怎么办呢!? 敲黑板啦~~
alter table IVYDD.EVAL_CONTACT move tablespace USERS lob(CONTEXT) store as (tablespace TBS_IVY);
Table altered
SQL> select segment_name, segment_type, tablespace_name from user_segments;
SEGMENT_NAME SEGMENT_TY TABLESPACE_NAME
------------------------------ ---------- ------------------------------
EVAL_CONTACT TABLE TBS_IVY
SYS_LOB0000089558C00006 LOBSEGMENT TBS_IVY
SYS_IL0000089558C00006 LOBINDEX TBS_IVY
使用alter table xxx move lob(xx) store as xxx (tablespace xxx);命令,我们可以进行lob列的存储位置调节。
在创建数据表的时候,同样可以使用lob(xxx)对应的数据表空间字句,执行存储lob对象的空间信息。
心得
在实际物理设计部署过程中,经常有将大对象分区和存储单独部署表空间的情况。可以根据实际的情况,将一些很大的lob列连同索引保存在单独的表空间上。
但是注意,一般数据表而言,lob段和lobindex段是在一个表空间上。即使在SQL语法上存在支持,但是将lob段和lobindex分开存储的语句通常被忽略掉。
alter table IVYDD.TABLE_NAME move tablespace TBS_TARGET;
alter table IVYDD.TABLE_NAME move tablespace USERS lob(LOG_COL) store as (tablespace TBS_TARGET);