oracle数值类型--LOB+ROWID/UROWID

Oracle中支持4种类型的LOB:
CLOB:字符LOB。存储大量的文本信息,如XML或者只是纯文本。这个数据类型须要进行字符集转换,也就是说,在获取时,这个字段中的字符会从数据库的字符集转换为客户的字符集,而在修改时会从客户的字符集转换为数据库的字符集。
NCLOB:这是另外一种类型的字符LOB。存储在这一列中的数据所采用的字符集是数据库的国家字符集,而不是数据库的默认字符集。
BLOB:二进制LOB。存储大量的二进制信息,如字处理文档,图像换。应用向BLOB中写入什么位和字节,BLOB就会返回什么为和字节。
BFILE:二进制文件LOB。带BFILE列的数据库中存储的只是操做系统中某个文件的一个指针。这个文件在数据库以外维护,根本不是数据库的一部分。BFILE提供了文件内容的只读访问。sql

1 内部LOB

scott@ORCL>create table t
  2  ( id int primary key,
  3     txt clob
  4  )
  5  /

表已建立。

scott@ORCL>select dbms_metadata.get_ddl( 'TABLE', 'T' )
  2  from dual;

DBMS_METADATA.GET_DDL('TABLE','T')
--------------------------------------------------------------------------------


  CREATE TABLE "SCOTT"."T"
   (    "ID" NUMBER(*,0),
        "TXT" CLOB,
         PRIMARY KEY ("ID")
  USING INDEX PCTFREE 10 INITRANS 2 MAXTRANS 255 NOCOMPRESS LOGGING
  TABLESPACE "TOOLS"  ENABLE
   ) SEGMENT CREATION DEFERRED
  PCTFREE 10 PCTUSED 40 INITRANS 1 MAXTRANS 255 NOCOMPRESS LOGGING
  TABLESPACE "TOOLS"
 LOB ("TXT") STORE AS BASICFILE (
  TABLESPACE "TOOLS" ENABLE STORAGE IN ROW CHUNK 8192 RETENTION
  NOCACHE LOGGING )

LOB显然有如下属性:
一个表空间(这个例子中即为TOOLS)
ENABLE STORAGE IN ROW做为一个默认属性
CHUNK 8192
RETENTION
NOCACHE
LOB列老是会带来一种多段对象(multisegment object),这个表会使用多个物理段数据库

实际LOB数据存储在lobsegment中,lobindex用于执行LOB的导航,来找出其中的某些部分。建立一个LOB列时,通常来讲,存储在行中的这是一个指针(pointer),或LOB定位器(LOB locator)。应用所获取的就是这个LOB定位器。当请求获得LOB的“1,2000~2,000字节”时,将对lobindex使用LOB定位器来找出这些字节存储在哪里,而后再访问lobsegment。能够用lobindex很容易地找到LOB的各个部分。能够把LOB想成是一种主/明细关系。LOB按“块”(chunk)或(piece)来存储,每一个片断均可以访问。例如,若是咱们使用表来实现一个LOB,能够以下作到这一点:缓存

Create table parent
( id int primary key,
other-data...
);
Create table lob
( id references parent on delete cascade,
chunk_number int,
data <datatype>(n),
primary key (id,chunk_number)
);

从概念上讲,LOB的存储与之很是类似,建立这两个表时,在LOB表的ID.CHUNK_NUMBER上要有一个主键(这对应于Oracle建立的lobindex),并且要有一个LOB表来存储数据块(对应于lobsegment)。LOB列为咱们透明地实现了这种主/明细结构。session

1. LOB表空间

从DBMS_METADATA返回的CREATE TABLE语句包括如下内容:并发

LOB ("TXT") STORE AS BASICFILE (TABLESPACE "TOOLS"....

TABLESPACE 存储lobsegment和lobindex表空间,这可能与表自己所在的表空间不一样。也就是说,保存LOB数据的表空间可能不一样于保存实际表数据的表空间。从管理的角度看,LOB数据类型表示一种规模很大的信息。若是表有数百万行,而每行有一个很大的LOB,那么LOB就会极为庞大。为LOB数据单独使用一个表空间有利于备份和恢复以及空间管理,将表与LOB数据分离就颇有意义。例如,LOB数据使用另一个统一的区段大小,而不是普通表数据所用的区段大小。另外一个缘由则出于I/O性能的考虑。默认状况下,LOB不在缓冲区缓存中进行缓存。所以,默认状况下,对于每一个LOB访问,不管是读仍是写,都会带来一个物理I/O(从磁盘直接读,或者向磁盘直接写)app

LOB多是内联的(inline),或者存储在表中。在这种状况下,LOB数据会被缓存,可是这只适用于小于4,000字节的LOB。async

lobindex和lobsegment老是会在同一个表空间中。实际上,lobindex的全部存储特征都是从lobsegment继承的。函数

2. IN ROW子句

前面的DBMS_METADATA返回的CREATE TABLE语句还包括如下内容:oop

LOB ("TXT") STORE AS BASICFILE (...ENABLE STORAGE IN ROW ...

这控制了LOB数据是否总与表分开存储(存储在lobsegment中),或是有时能够与表一同存储,而不用单独放在lobsegment中。若是设置了ENABLE STORAGE IN ROW,而不是DISABLE STORAGE IN ROW,小LOB(最多4,000字节)就会像VARCHAR2同样存储在表自己中。只有当LOB超过了4,000字节时,才会“移出”到lobsegment中。性能

默认行为是启用行内存储(ENABLE STORAGE IN ROW),并且通常来说,若是知道LOB老是能在表自己中放下,就应该采用这种默认行为,这样既能避免单独存储的开销,又能避免获取LOB时所需的物理I/O。

咱们将建立包括有两个LOB的表,其中一个LOB能够在行内存储数据,而另外一个LOB禁用了行内存储:

scott@ORCL>create table t
  2  ( id int primary key,
  3     in_row clob,
  4     out_row clob
  5  )
  6  lob (in_row) store as ( enable storage in row )
  7  lob (out_row) store as ( disable storage in row )
  8  /

表已建立。

在这个表中,咱们将插入一些串数据,全部这些串的长度都不超过4,000字节:

scott@ORCL>insert into t
  2     select rownum,
  3             owner || ' ' || object_name || ' ' || object_type || ' ' || status,
  4             owner || ' ' || object_name || ' ' || object_type || ' ' || status
  5     from all_objects
  6  /

已建立72081行。

scott@ORCL>commit;

提交完成。

如今,想读取每一行,在此使用了DBMS_MONITOR包,并启用了SQL_TRACE(具体参见 tkprof 性能分析 ),执行这个工做时,能够看到这两个表获取数据时的性能:

SELECT IN_ROW 
FROM
 T WHERE ID = :B1 

call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse        1      0.00       0.00          0          0          0           0
Execute  72081      1.09       1.28          0          0          0           0
Fetch    72081      1.18       1.11          0     216243          0       72081
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total   144163      2.27       2.40          0     216243          0       72081

Misses in library cache during parse: 0
Optimizer mode: ALL_ROWS
Parsing user id: 84     (recursive depth: 1)

Rows     Row Source Operation
-------  ---------------------------------------------------
      1  TABLE ACCESS BY INDEX ROWID T (cr=3 pr=0 pw=0 time=0 us cost=1 size=2015 card=1)
      1   INDEX UNIQUE SCAN SYS_C0020634 (cr=2 pr=0 pw=0 time=0 us cost=1 size=0 card=1)(object id 85254)

********************************************************************************
SELECT OUT_ROW 
FROM
 T WHERE ID = :B1 

call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse        1      0.00       0.00          0          0          0           0
Execute  72081      1.13       0.88          0          0          0           0
Fetch    72081      7.47      26.76      72081     504567          0       72081
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total   144163      8.61      27.65      72081     504567          0       72081

Misses in library cache during parse: 0
Optimizer mode: ALL_ROWS
Parsing user id: 84     (recursive depth: 1)

Rows     Row Source Operation
-------  ---------------------------------------------------
      1  TABLE ACCESS BY INDEX ROWID T (cr=3 pr=0 pw=0 time=0 us cost=1 size=253 card=1)
      1   INDEX UNIQUE SCAN SYS_C0020634 (cr=2 pr=0 pw=0 time=0 us cost=1 size=0 card=1)(object id 85254)


Elapsed times include waiting on following events:
  Event waited on                             Times   Max. Wait  Total Waited
  ----------------------------------------   Waited  ----------  ------------
  Disk file operations I/O                        1        0.00          0.00
  direct path read                            72008        0.18         18.79

获取IN_ROW列显著地快得多,并且所占用的资源也远远少于OUT_ROW列。能够看到,它使用了216,243次逻辑I/O(查询模式获取),而OUT_ROW列使用的逻辑I/O次数是它的两倍。这些额外的逻辑I/O 是对lobindex段的I/O(为了找到LOB的各个部分)。

另外,能够看到,对于OUT_ROW列,获取72081行会带来72081次物理I/O,而这会致使一样数目的“直接路径读”I/O等待。这些都是对非缓存LOB数据的读取。在这种状况下,经过启用LOB数据的缓存,能够缓解这个问题,可是这样一来,咱们又必须确保为此要有足够多的额外的缓冲区缓存。另外,若是确实有很是大的LOB,咱们可能并不但愿缓存这些数据。

这种行内/行外存储设置不只会影响读,还会影响修改。若是咱们要用小串更新前100行,并用小串插入100个新行,再使用一样的技术查看性能,会观察到:

scott@ORCL>alter system set timed_statistics=true scope=both;

系统已更改。

scott@ORCL>alter session set sql_trace = true;

会话已更改。

scott@ORCL>create sequence s start with 100000;

序列已建立。

scott@ORCL>declare
  2     l_cnt number;
  3     l_data varchar2(32765);
  4  begin
  5     dbms_monitor.session_trace_enable;
  6     for i in 1 .. 100
  7     loop
  8             update t set in_row =
  9                     to_char(sysdate,'dd-mon-yyyy hh24:mi:ss') where id = i;
 10             update t set out_row =
 11                     to_char(sysdate,'dd-mon-yyyy hh24:mi:ss') where id = i;
 12             insert into t (id, in_row) values ( s.nextval, 'Hello World' );
 13             insert into t (id,out_row) values ( s.nextval, 'Hello World' );
 14     end loop;
 15     end;
 16  /

PL/SQL 过程已成功完成。

scott@ORCL>show parameter user_dump_dest;

NAME                        TYPE      VALUE
------------------------    ------    ------------------------------------
user_dump_dest\diag\rdbm    string    d:\app\administrators\orcl\orcl\trace

                                                            
scott@ORCL> select username,sid,serial# from v$session where username='SCOTT';

USERNAME   SID    SERIAL#
--------  -----   --------
SCOTT      11     108


scott@ORCL>select 'orcl_ora_'||spid||'.trc' from v$process where addr = (select
paddr from v$session where sid=11);

'ORCL_ORA_'||SPID||'.TRC'
--------------------------------------------------------------------------
orcl_ora_4000.trc

scott@ORCL>alter session set sql_trace = false;

会话已更改。

scott@ORCL>exit
从 Oracle Database 11g Enterprise Edition Release 11.2.0.1.0 - 64bit Production
With the Partitioning, OLAP, Data Mining and Real Application Testing options 断
开

C:\Users\Administrator>d:

D:\>cd app\Administrator\diag\rdbms\orcl\orcl\trace

D:\app\Administrator\diag\rdbms\orcl\orcl\trace>tkprof orcl_ora_4000.trc f:\2018
0906.txt

TKPROF: Release 11.2.0.1.0 - Development on 星期四 9月 6 14:32:55 2018

Copyright (c) 1982, 2009, Oracle and/or its affiliates.  All rights reserved.



D:\app\Administrator\diag\rdbms\orcl\orcl\trace>

在获得的TKPROF报告中能够观察到相似的结果:

UPDATE T SET IN_ROW = TO_CHAR(SYSDATE,'dd-mon-yyyy hh24:mi:ss') 
WHERE
 ID = :B1 


call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse        1      0.00       0.00          0          0          0           0
Execute    100      0.01       0.04          0        201        208         100
Fetch        0      0.00       0.00          0          0          0           0
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total      101      0.01       0.04          0        201        208         100

Misses in library cache during parse: 1
Misses in library cache during execute: 1
Optimizer mode: ALL_ROWS
Parsing user id: 84     (recursive depth: 1)

Rows     Row Source Operation
-------  ---------------------------------------------------
      0  UPDATE  T (cr=3 pr=0 pw=0 time=0 us)
      1   INDEX UNIQUE SCAN SYS_C0020634 (cr=2 pr=0 pw=0 time=0 us cost=1 size=2015 card=1)(object id 85254)


Elapsed times include waiting on following events:
  Event waited on                             Times   Max. Wait  Total Waited
  ----------------------------------------   Waited  ----------  ------------
  direct path write                              84        0.00          0.02
  asynch descriptor resize                      163        0.00          0.00
********************************************************************************
UPDATE T SET OUT_ROW = TO_CHAR(SYSDATE,'dd-mon-yyyy hh24:mi:ss') 
WHERE
 ID = :B1 


call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse        1      0.00       0.00          0          0          0           0
Execute    100      0.01       0.11          3       1657       2606         100
Fetch        0      0.00       0.00          0          0          0           0
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total      101      0.01       0.11          3       1657       2606         100

Misses in library cache during parse: 1
Misses in library cache during execute: 1
Optimizer mode: ALL_ROWS
Parsing user id: 84     (recursive depth: 1)

Rows     Row Source Operation
-------  ---------------------------------------------------
      0  UPDATE  T (cr=12 pr=1 pw=1 time=0 us)
      1   INDEX UNIQUE SCAN SYS_C0020634 (cr=2 pr=0 pw=0 time=0 us cost=1 size=253 card=1)(object id 85254)


Elapsed times include waiting on following events:
  Event waited on                             Times   Max. Wait  Total Waited
  ----------------------------------------   Waited  ----------  ------------
  Disk file operations I/O                        2        0.00          0.00
  db file sequential read                         1        0.02          0.02
  direct path write                              10        0.00          0.00
  asynch descriptor resize                       18        0.00          0.00

能够看到,行外LOB的更新占用了更多的资源。它要花必定的时间完成直接路径写(物理I/O),并执行更多的当前模式获取以及查询模式获取。这些都源于一点,即除了维护表自己外,还必须维护lobindex和lobsegment。INSERT操做也显示出了一样的差别:

INSERT INTO T (ID, IN_ROW) 
VALUES
 ( S.NEXTVAL, 'Hello World' )


call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse        1      0.00       0.00          0          0          0           0
Execute    100      0.00       0.01          1          3        324         100
Fetch        0      0.00       0.00          0          0          0           0
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total      101      0.00       0.01          1          3        324         100

Misses in library cache during parse: 1
Optimizer mode: ALL_ROWS
Parsing user id: 84     (recursive depth: 1)

Rows     Row Source Operation
-------  ---------------------------------------------------
      0  LOAD TABLE CONVENTIONAL  (cr=2 pr=1 pw=0 time=0 us)
      1   SEQUENCE  S (cr=1 pr=0 pw=0 time=0 us)


Elapsed times include waiting on following events:
  Event waited on                             Times   Max. Wait  Total Waited
  ----------------------------------------   Waited  ----------  ------------
  db file sequential read                         3        0.01          0.01
  direct path write                              92        0.00          0.02
  asynch descriptor resize                      178        0.00          0.00
********************************************************************************
INSERT INTO T (ID,OUT_ROW) 
VALUES
 ( S.NEXTVAL, 'Hello World' )


call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse        1      0.00       0.00          0          0          0           0
Execute    100      0.03       0.10          1       1188       1947         100
Fetch        0      0.00       0.00          0          0          0           0
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total      101      0.03       0.10          1       1188       1947         100

Misses in library cache during parse: 1
Optimizer mode: ALL_ROWS
Parsing user id: 84     (recursive depth: 1)

Rows     Row Source Operation
-------  ---------------------------------------------------
      0  LOAD TABLE CONVENTIONAL  (cr=11 pr=0 pw=1 time=0 us)
      1   SEQUENCE  S (cr=0 pr=0 pw=0 time=0 us)


Elapsed times include waiting on following events:
  Event waited on                             Times   Max. Wait  Total Waited
  ----------------------------------------   Waited  ----------  ------------
  direct path write                               1        0.00          0.00

注意读和写使用的I/O都有所增长。总之,由此显示出,若是使用一个CLOB,并且不少串都能在“行内”放下(也就是说,小于4,000字节),那么使用默认的ENABLE STORAGE IN ROW设置就是一个不错的想法。

3. CHUNK子句

前面的DBMS_METADATA返回的CREATE TABLE语句包括如下内容:

LOB ("TXT") STORE AS BASICFILE (...CHUNK 8192...

LOB存储在块(chunk)中;指向LOB数据的索引会指向各个数据块。块(chunk)是逻辑上连续的一组数据库块(block),这也是LOB的最小分配单元,而一般数据库的最小分配单元是数据库块。CHUNK大小必须是Oracle块大小的整数倍,只有这样才是合法值。
从两个角度看,选择CHUNK大小时必须小心。首先,每一个LOB实例(每一个行外存储的LOB值)会占用至少一个CHUNK。一个CHUNK有一个LOB值使用。若是一个表有100行,而每行有一个包含7KB数据的LOB,你就会分配100个CHUNK,若是将CHUNK大小设置为32KB,就会分配100个32KB的CHUNK。若是将CHUNK大小设置为8KB,则(可能)分配100个8KB的CHUNK。关键是,一个CHUNK只能有一个LOB使用(两个LOB不会使用同一个CHUNK)。若是选择了一个CHUNK大小,但不符合你指望的LOB大小,最后就会浪费大量的空间。例如,若是表中的LOB平均有7KB,而你使用的CHUNK大小为32KB,对于每一个LOB实例你都会“浪费”大约25KB的空间,另外一方面,假若使用8KB的CHUNK,就能使浪费减至最少。
还须要注意要让每一个LOB实例相应的CHUNK数减至最少。有一个lobindex用于指向各个块,块越多,索引就越大。若是有一个4MB的LOB,并使用8KB的CHUNK,你就至少须要512个CHUNK来存储这个消息。这也说明,至少须要512个lobindex条目指向这些CHUNK。另外,这还会影响获取性能,由于与读取更少但更大的CHUNK相比,如今要花更长的数据来读取和管理许多小CHUNK。咱们最终的目标是:使用一个能使“浪费”最少,同时又能高效存储数据的CHUNK大小。

4. PCTVERSION子句

控制LOB的读一致性。lobsegment并不使用undo来记录其修改;而是直接在lobsegment自己中维护信息的版本。lobindex会像其余段同样生成undo,可是lobsegment不会。相反,修改一个LOB时,Oracle会分配一个新的CHUNK,而且仍保留原来的CHUNK。若是回滚了事务,对LOB索引所作的修改会回滚,索引将再次指向原来的CHUNK。所以,undo维护会在LOB段自己中执行。修改数据时,原来的数据库保持不动,此外会建立新数据。

读LOB数据时这也很重要。LOB是读一致的,这与全部其余段同样。若是你在上午9:00获取一个LOB定位器,你从中获取的LOB数据就是“上午9:00那个时刻的数据”。这就像是你在上午9:00打开了一个游标(一个结果集)同样,所生成的行就是那个时间点的数据行。与结果集相似,即便别人后来修改了LOB数据。在此,Oracle会使用lobsegment,并使用logindex的读一致视图来撤销对LOB的修改,从而提取获取LOB定位器当时的LOB数据。它不会使用logsegment的undo信息,由于根本不会为logsegment自己生成undo信息。

能够很容易地展现LOB是读一致的,考虑如下这个小表,其中有一个行外LOB(存储在logsegment中):

scott@ORCL>create table t
  2  ( id int primary key,
  3     txt clob
  4  )
  5  lob( txt) store as ( disable storage in row )
  6  /

表已建立。

scott@ORCL>insert into t values ( 1, 'hello world' );

已建立 1 行。

scott@ORCL>commit;

提交完成。

若是取出LOB定位器,并在这个表上打开一个游标,以下:

scott@ORCL>declare
  2     l_clob clob;
  3
  4     cursor c is select id from t;
  5     l_id number;
  6
  7     begin
  8             select txt into l_clob from t; ## 取出LOB定位器
  9             open c;                        ## 并在这个表上打开一个游标
 10
 11             update t set id = 2, txt = 'Goodbye'; ## 而后修改行,并提交
 12             commit;

 13             #经过使用LOB定位器和打开的游标,会提供“获取LOB定位器或打开游标那个时间点”的数据
 14             dbms_output.put_line( dbms_lob.substr( l_clob, 100, 1 ) );
 15             fetch c into l_id;
 16             dbms_output.put_line( 'id = ' || l_id );
 17             close c;
 18     end;
 19  /
hello world
id = 1

PL/SQL 过程已成功完成。

可是数据库中的数据极可能已经更新/修改:

scott@ORCL>select * from t;

        ID TXT
---------- --------
         2 Goodbye

游标C的读一致映像来自undo段,而LOB的读一致映像则来自LOB段自己。

PCTVERSION控制着用于实现LOB数据版本化的已分配LOB空间的百分比(这些数据库块由某个时间点的LOB所用,并处在lobsegment的HWM如下)。对于许多使用状况来讲,默认设置12%就足够了,由于在不少状况下,只是要INSERT和获取LOB(一般不会执行LOB的更新;LOB每每会插入一次,而获取屡次)。所以,没必要为LOB版本化预留太多的空间(甚至能够没有)。

不过,若是应用确实常常修改LOB,假若频繁地读LOB,与此同时另外某个会话正在修改这些LOB,12%可能就过小了。若是处理LOB时遇到一个ORA-22924错误,解决方案不是增长undo表空间的大小,也不是增长undo保留时间(UNDO_RETENTION),若是你在使用手动undo管理,那么增长更多RBS空间也不能解决这个问题。而是应该使用如下命令:

ALTER TABLE tabname MODIFY LOB (lobname) ( PCTVERSION n );

并增长lobsegment中为实现数据版本化所用的空间大小。

5. RETENTION子句

前面的DBMS_METADATA返回的CREATE TABLE语句包括如下内容:

LOB ("TXT") STORE AS BASICFILE (... RETENTION ...

这个子句与PCTVERSION子句是互斥的,若是数据库中使用自动undo管理,就可使用这个子句。RETENTION子句在lobsegment中使用基于时间的机制来保留数据。数据库会设置参数UNDO_RETENTION,指定要把undo信息保留多长时间来保证一致读。在这种状况下,这个参数也适用于LOB数据。
不能使用这个子句来指定保留时间;而要从数据库的UNDO_RETENTION设置来继承它。

6. CACHE子句

前面的DBMS_METADATA返回的CREATE TABLE语句包括如下内容:

LOB ("TXT") STORE AS BASICFILE (... NOCACHE ...

除了NOCACHE,这个选项还能够是CACHECACHE READS。这个子句控制了lobsegment数据是否存储在缓冲区缓存中。默认的NOCACHE指示,每一个访问都是从磁盘的一个直接读,相似地,每一个写/修改都是对大盘的一个直接写。CACHE READS容许缓存从磁盘读的LOB数据,可是LOB数据的写操做必须直接写至磁盘。CACHE则容许读和写时都能缓存LOB数据。
若是只有小规模或中等规模的LOB(例如,使用LOB来存储只有几KB的描述性字段),对其缓存就颇有意义。若是不缓存,当用户更新描述字段时,还必须等待I/O将数据写指磁盘(将执行一个CHUNK大小的I/O,并且用户要等待这个I/O完成)。若是你在执行多个LOB的加载,那么加载每一行时都必须等待这个I/O完成。因此启用执行LOB缓存很合理。能够打开和关闭缓存,来看看会有什么影响:

ALTER TABLE tabname MODIFY LOB (lobname) ( CACHE );
ALTER TABLE tabname MODIFY LOB (lobname) ( NOCACHE );

对于一个规模不少的初始加载,启用LOB的缓存颇有意义,这容许DBWR在后台将LOB数据写至磁盘,而客户应用能够继续加载更多的数据。对于频繁访问或修改的小到中等规模的LOB,缓存就很合理,能够部门让最终用户实时等待物理I/O完成。不过,对于一个大小为50MB的LOB,把它放在缓存中就没有道理了。
此时能够充分使用Keep池或回收池。并不是在默认缓存中将lobsegment数据与全部“常规”数据一同缓存,可使用保持池或回收池将其分开缓存。采用这种方式,既能缓存LOB数据,并且不影响系统中现有数据的缓存。

7. LOB STORAGE子句

它有一个完整的存储子句,能够用来控制物理存储特征。这个存储子句一样适用于lobsegment和lobindex,对一个段的设置也能够用于另外一个段。假设有一个本地管理的表空间,LOB的相关设置将是FREELISTS、FREELIST GROUPS和BUFFER_POOL。FREELISTS和FREELIST GROUPS与表段的关系 一样适用于lobindex段,由于lobindex与其余索引段的管理是同样的。若是须要高度并发地修改LOB,可能最好在索引段上设置多个FREELISTS。
对LOB段使用保持池或回收池多是一个颇有用的技术,这样就能缓存LOB数据,并且不会“破坏”现有的默认缓冲区缓存。并非将LOB与常规表一同放在块缓冲区中,能够在SGA中专门为这些LOB对象预留一段专用的内存。BUFFER_POOL子句能够达到这个目的。

2. BFILE

BFILE类型只是操做系统上一个文件的指针。它用于为这些操做系统文件提供只读访问。

使用BFILE时,还有使用一个Oracle DIRECTORY对象。DIRECTORY对象只是将一个操做系统目录映射至数据库中的一个“串”或一个名称(以提供可移植性;你可能想使用BFILE中的一个串,而不是操做系统特定的文件名约定)。做为一个小例子,下面建立一个带BFILE列的表,并建立一个DIRECTORY对象,再插入一行,其中引用了文件系统中的一个文件:

scott@ORCL>create table t
  2  ( id int primary key,
  3     os_file bfile
  4  )
  5  /

表已建立。

scott@ORCL>create or replace directory my_dir as '/tmp/'
  2  /

目录已建立。

scott@ORCL>insert into t values ( 1, bfilename( 'MY_DIR', 'test.dbf' ) );

已建立 1 行。

如今,就能够把BFILE当成一个LOB来处理,由于它就是一个LOB。例如,能够作下面的工做:

scott@ORCL>create or replace directory MY_DIR as 'd:/test';

目录已建立。

scott@ORCL>insert into t values ( 1, bfilename( 'MY_DIR', '11.txt'));

已建立 1 行。

scott@ORCL>select dbms_lob.getlength(os_file) from t;

DBMS_LOB.GETLENGTH(OS_FILE)
---------------------------
                         28

能够看到所指定的文件大小为28kb。若是使用混合大小写或小写,会获得如下错误:

scott@ORCL>update t set os_file = bfilename( 'my_dir', '11.txt' );

已更新 1 行。

scott@ORCL>select dbms_lob.getlength(os_file) from t;
select dbms_lob.getlength(os_file) from t
       *
第 1 行出现错误:
ORA-22285: 对不存在的目录或文件进行 GETLENGTH 操做
ORA-06512: 在 "SYS.DBMS_LOB", line 787

Oracle中的DIRECTORY对象是标识符,而默认状况下标识符都以大写形式存储。BFILENAME内置函数接受一个串,这个串的大小写必须与数据字典中存储的DIRECTORY对象的大小写彻底匹配。因此,必须在BFILENAME函数中使用大写,或者在建立DIRECTORY对象时使用加引号的标识符

scott@ORCL>create or replace directory "my_dir" as 'd:/test';

目录已建立。

scott@ORCL>select dbms_lob.getlength(os_file) from t;

DBMS_LOB.GETLENGTH(OS_FILE)
---------------------------
                         28

不建议使用加引号的标识符;而倾向于在BFILENAME调用中使用大写。加引号的标识符属于“异类”,可能会在之后致使混淆。
BFILE在磁盘上占用的空间不定,这取决于DIRECTORY对象名的文件名的长度。
与其余LOB数据不一样,BFILE数据不是“读一致”的。因为BFILE在数据库以外管理,对BFILE解除引用时,不论文件上发生了什么,都会反映到获得的结果中。因此,若是反复读同一个BFILE,可能会产生不一样的结果,这与对CLOB、BLOB或NCLOB使用LOB定位器不一样。

ROWID/UROWID类型

ROWID是数据库中一行的地址。ROWID中编入了足够多的信息,足以在磁盘上找到行,以及标识ROWID所指向的对象(表等)。ROWID有一个“近亲”UROWID,它用于表,如IOT和经过异构数据库网关访问的没有固定ROWID表。UROWID是行主键值的一个表示,所以,其大小不定,这取决于它指向的对象。

每一个表中的每一行都有一个与之关联的ROWID或UROWID从表中获取时,把它们看做为伪列(pseudo column),这说明它们并不真正存储在行中,而是行的一个推导属性。ROWID基于行的物理位置生成;它并不随行存储。UROWID基于行的主键生成,因此从某种意义上讲,好像它是随行存储的,可是事实上并不是如此,由于UROWID并不做为一个单独的列存在,而只是做为现有列的一个函数。
之前ROWID是不可变的。插入一行时,会为之关联一个ROWID(一个地址),并且这个ROWID会一直与该行关联,直到这一行被删除(被物理地从数据库删除)。可是,后来状况发生了变化,由于如今有些操做可能会致使行的ROWID改变,例如:
在分区表中更新一行的分区键,使这一行必须从一个分区移至另外一个分区。
使用FLASHBACK TABLE命令将一个数据库表恢复到之前的每一个时间点。
执行MOVE操做以及许多分区操做,如分解或合并分区。
使用ALTER TABLE SHRINK SPACE命令执行段收缩。
现在,因为ROWID可能过一段时间会改变(由于它再也不是不可变的),因此不建议把它们做为单独的列物理地存储在数据库表中。也就是说,使用ROWID做为一个数据库列的数据类型被认为是一种很差的实践作法。应当避免这种作法,而应使用行的主键(这应该是不可变的),另外引用完整性能够确保数据的完整性。对此用ROWID类型是作不到的,不能用ROWID建立从子表到一个父表的外键,并且不能保证跨表的完整性。你必须使用主键约束。
ROWID做为行的一个物理地址,要访问任何表中的某一行,这是最快的方法。若是应用从数据库读出数据并将其提供给最终用户,它试图更新这一行时就可使用ROWID。应用这种方式,只需最少的工做就能够更新当前行(例如,不须要索引查找再次寻找行),并经过验证行值未被修改来确保这一行与最初读出的行是同一行。因此,在采用乐观锁定的应用中ROWID仍是有用的。

相关文章
相关标签/搜索