在 oracle中,为数据表字段column和pl/sql语言,分别提供了多种数据类型,以应对实际开发中的多种类型。lob类型是oracle推出一种保存大对象的数据类型。当我们考虑将信息文件(十进制、二进制)、图像甚至音频信息采用数据库作为保存载体时,就需要使用lob
在oracle中,为数据表字段column和pl/sql语言,分别提供了多种数据类型,以应对实际开发中的多种类型。lob类型是oracle推出一种保存大对象的数据类型。当我们考虑将信息文件(十进制、二进制)、图像甚至音频信息采用数据库作为保存载体时,就需要使用lob类型数据。
目前oracle支持的lob类型具体包括四个子类型(subtype),分别为clob、blob、nlob和bfile。其中,clob、blob和nlob都是将数据保存在数据库内部,而bfile类型保存的核心是文件指针,真正的文件是保存在数据库外。
与传统的数据类型相比较,lob类型数据无论在管理上还是空间使用上,都有很多特殊之处。本篇主要介绍lob类型一些基本的存储特性。
1、 环境准备和数据段segment特性我们选择在oracle 10gr2下进行试验。
sql> select * from v$version;
banner
----------------------------------------------------------------
oracle database 10g enterprise edition release 10.2.0.1.0 - prod
pl/sql release 10.2.0.1.0 - production
core 10.2.0.1.0 production
tns for 32-bit windows: version 10.2.0.1.0 - production
nlsrtl version 10.2.0.1.0 – production
使用create table命令,可以构建出一个实验数据表t。
sql> create table t (id number,cl clob);
table created
对于一般的数据表而言,一个数据表只会对应一个存储数据段data segment对象。这里的特殊情况是分区表,通常一个分区就对应一个单独的存储对象。当数据表中包括lob类型的数据列时,也会有独特的段对象建立。
sql> select segment_name, segment_type, tablespace_name from user_segments;
segment_name segment_ty tablespace_name
------------------------------ ---------- ------------------------------
sys_lob0000056069c00002$$ lobsegment users
t table users
sys_il0000056069c00002$$ lobindex users
(篇幅原因,无关对象省略。。。。。。)
9 rows selected
我们发现,除了常规的数据段t之外,另外增加了两个明显是系统命名的段对象,类型分别为lobsegment和lobindex。
对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列共生,如果强制进行删除操作,是会报错的。
sql> drop index sys_il0000056069c00002$$;
drop index sys_il0000056069c00002$$
ora-22864: 无法 alter 或 drop lob 索引
2、lob类型数据表原始定义分析使用dbms_metadata包,我们可以获取到数据表的全部定义,包括各种缺省参数和细节信息。
create table scott.t
( id number,
cl 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 (cl) store as (
tablespace users enable storage in row chunk 8192 pctversion 10
nocache logging
storage(initial 65536 next 1048576 minextents 1 maxextents 2147483645
pctincrease 0 freelists 1 freelist groups 1 buffer_pool default)) ;
create unique index scott.sys_il0000056069c00002$$ on scott.t (
pctfree 10 initrans 2 maxtrans 255
storage(initial 65536 next 1048576 minextents 1 maxextents 2147483645
pctincrease 0 freelists 1 freelist groups 1 buffer_pool default)
tablespace users
parallel (degree 0 instances 0) ;
可以看到我们抽取出的元数据包括两个组成部分,数据表创建部分和lob索引创建部分。在数据表创建部分,我们可以看到将lob作为一个独立段对象进行存储设置和参数设置。
在lob索引创建部分,我们可以看到虽然是对应索引创建语句,但是从索引名称上显然是系统自动生成的对象名称
此外,还有很多是针对lob特殊的参数,如cache、enable storage in-row等,这些参数在数据表lob的行为和访问性能上有巨大的影响。由于篇幅和内容所限,我们在本篇中不加以累述。
3、lob段与lob索引存储转移
对于一个数据表涉及的多个段,很多时候我们需要将其进行移动处理。其中最常用的方法是使用move进行对象表空间的移动。
sql> select segment_name, segment_type, tablespace_name from user_segments;
segment_name segment_ty tablespace_name
------------------------------ ---------- ------------------------------
sys_lob0000056099c00002$$ lobsegment users
t table users
sys_il0000056099c00002$$ lobindex users
9 rows selected
sql> alter table t move tablespace system;
table altered
sql> select segment_name, segment_type, tablespace_name from user_segments;
segment_name segment_ty tablespace_name
------------------------------ ---------- ------------------------------
t table system
sys_lob0000056099c00002$$ lobsegment users
sys_il0000056099c00002$$ lobindex users
9 rows selected
上面实验可以明确看到,当使用一般的move命令时,只会将数据表t段进行移动到新表空间。lob段和对应的lobindex段没有变化。如果需要移动lob/lobindex,需要额外的单独操作。
sql> alter index sys_il0000056069c00002$$ rebuild tablespace users;
alter index sys_il0000056069c00002$$ rebuild tablespace users
ora-02327: 无法以数据类型 lob 的表达式创建索引
lobindex是不能使用rebuild直接重构的。
sql> select segment_name, segment_type, tablespace_name from user_segments;
segment_name segment_ty tablespace_name
------------------------------ ---------- ------------------------------
t_logsegment lobsegment users
sys_il0000056069c00002$$ lobindex users
t table example
9 rows selected
sql> alter table t move lob(cl) store as t_logsegment (tablespaceexample);
table altered
sql> select segment_name, segment_type, tablespace_name from user_segments;
segment_name segment_ty tablespace_name
------------------------------ ---------- ------------------------------
t table example
sys_il0000056069c00002$$ lobindex example
t_logsegment lobsegmentexample
9 rows selected
使用alter table xxx move lob(xx) store as xxx (tablespace xxx);命令,我们可以进行lob列的存储位置调节。
在创建数据表的时候,同样可以使用lob(xxx)对应的数据表空间字句,执行存储lob对象的空间信息。
sql> create table demolob ( a number, b clob )
2 lob(b)
3 store as lobsegname (
4 tablespace users
5 --storage (lobsegment storage clause)
6 index lobindexname (
7 tablespace example
8 --storage ( lobindex storage clause )
9 )
10 )
11 tablespace system
12 --storage( tables storage clause )
13 ;
table created
sql> select table_name, column_name, segment_name, tablespace_name, index_name from user_lobs;
table_name column_nam segment_name tablespace_name index_name
---------- ---------- ------------------------------ ------------------------------ ------------------------------
t cl t_logsegment example sys_il0000056069c00002$$
在实际物理设计部署过程中,经常有将大对象分区和存储单独部署表空间的情况。可以根据实际的情况,将一些很大的lob列连同索引保存在单独的表空间上。
但是注意,一般数据表而言,lob段和lobindex段是在一个表空间上。即使在sql语法上存在支持,但是将lob段和lobindex分开存储的语句通常被忽略掉。
sql> alter table t move lob(cl) store as t_logsegment (tablespace example index t_logindex (tablespace users));
table altered
sql> select table_name, column_name, segment_name, tablespace_name, index_name from user_lobs;
table_name column_nam segment_name tablespace_name index_name
---------- ---------- ------------------------------ ------------------------------ ------------------------------
t cl t_logsegment example sys_il0000056069c00002$$
sql> select segment_name, segment_type, tablespace_name from user_segments;
segment_name segment_ty tablespace_name
------------------------------ ---------- ------------------------------
t table example
sys_il0000056069c00002$$ lobindex example
t_logsegment lobsegment example
9 rows selected
4、结论
lob类型是一种我们经常使用的复杂数据类型。处理和管理lob类型的方法和我们常规的手段存在很大差异,无论是开发还是运维过程中都要特别注意。