深入SecureFile—新一代LOB揭秘000

编写人:常伟俊
审核人:张陈亚
在Oracle8i 中,LOB 设计是基于下列假设做出的:
(1) LOB 实例化的大小预计为几个兆字节。
(2) LOB 通常被视为“单写多读”类型的数据。很少进行更新,所以可以为所有类型的更新(大型或小型)对整个块进行版本化。
(3) 预计很少有批处理会流式处理数据。预计不会出现联机事务处理(OLTP) 类型的工作量。
(4) 保留的还原量由用户使用PCTVERSION 和RETENTION 参数进行控制。这是额外的管理工作。
(5) 在假设LOB 大小通常是统一的前提下,CHUNK 大小是一个静态参数。CHUNK 大小的上限是32 KB。
(6) 预计Oracle RAC 中不会出现高并发性的写入。
自首次实施后,业务要求已发生了显著变化。现在LOB 的使用方式与关系数据的相似,用于存储各种大小的半结构化和非结构化数据。数据大小可以从几千字节(用于HTML 链接)到几兆兆字节(用于流视频)不等。
在LOB 中存储所有文件系统数据的Oracle 文件系统会遇到类似OLTP 的高并发性访问。随着Oracle RAC 日益广泛的应用,必须解决OracleRAC 的可扩展性问题。LOB 空间结构的现有设计不能满足这些新要求。
Oracle SecureFiles 说明
Oracle Database 11g 将LOB 数据类型作为Oracle SecureFiles 进行了完全重新设计,显著改进了应用程序开发的性能、可管理性和易用性。新实施也提供了下一代高级功能,如智能压缩和透明加密。
使用SecureFiles 时,块大小介于Oracle 数据块大小到64MB 之间。Oracle DB 尝试使数据集中在磁盘的相邻物理位置,从而将内部碎片降到最低。通过使用可变的块大小,SecureFiles 避免对不必要的大型LOB 数据块进行版本化。
SecureFiles 还提供了新的客户机/服务器网络层,从而允许在支持更高读写性能的服务器和客户机之间进行高速数据传输。SecureFiles自动确定生成重做和还原的最有效方法,因而不需要用户定义参数。SecureFiles 自动确定是仅为更改生成重做和还原,还是通过生成完整的重做记录创建新版本。
由于SecureFiles 需要维护各种内存中统计信息以帮助有效地分配内存和空间,所以将其设计为可自适应的智能工具。这样,由于减少了很难使用不可预测的负荷进行优化的可优化参数数量,可管理性有所提高。
Oracle SecureFiles 重新设计了非结构化(文件)数据的处理方法,提供了以下全新的设计:
(1) 磁盘格式
a) 可变块大小
(2) 网络协议
a) 改进的输入/输出
(3) 版本化和共享机制
(4) 重做和还原算法
a) 无用户配置
(5) 空间和内存增强功能
1.3 启用SecureFiles 存储
使用DB_SECUREFILE 初始化参数,数据库管理员(DBA) 可确定SecureFiles 的使用情况,其中有效值为:
(1) ALWAYS:尝试将ASSM表空间上的所有LOB 创建为SecureFile LOB,但是仅可将自动段空间管理(ASSM) 表空间外的任何LOB 创建为BasicFile LOB
(2) FORCE:强制将所有LOB 创建为SecureFileLOB
(3) PERMITTED:允许创建SecureFiles(默认值)
(4) NEVER:禁止创建SecureFiles
(5) IGNORE:禁止创建SecureFiles,并忽略使用SecureFiles 选项强制创建BasicFiles 而导致的任何错误
如果指定了NEVER,则任何指定为SecureFiles 的LOB 均被创建为BasicFiles。如果对BasicFiles 使用任何SecureFiles 特定的存储选项和功能(如压缩、加密和取消重复),则会导致异常错误。将对任何未指定的存储选项使用BasicFiles 默认值。
如果指定了ALWAYS,则系统中创建的所有LOB 均会被创建为SecureFiles。必须在ASSM 表空间中创建LOB,否则会发生错误。将忽略所有指定的BasicFiles 存储选项。可以使用ALTER SYSTEM 命令更改所有存储的SecureFiles 默认值。

SQL>Altersystem set db_securefile=’ALWAYS’;

1.4 SecureFiles:高级功能

OracleSecureFiles 实施也提供了下一代高级功能,如智能压缩和透明加密。压缩功能支持显式压缩SecureFiles。SecureFiles 仅为随机读取或写入访问透明解压缩所需的数据块集,从而自动维护未压缩和已压缩的偏移量之间的映射。如果将压缩级别从MEDIUM 更改为HIGH,则映射会自动进行更新以反映新的压缩算法。取消重复可自动检测重复的SecureFile LOB 数据,并通过仅存储一个副本来节省空间- 减少磁盘存储空间、I/O 和重做事件记录。可在表级别或分区级别指定取消重复,但不能跨越分区的LOB。取消重复需要使用高级压缩选项。
现在可以在适当位置存储加密的LOB数据,并对其进行随机读取和写入,因而提高了数据的安全性。只能按列加密SecureFile LOB (与透明数据加密相同)。将使用相同的加密算法对LOB 列中的所有分区进行加密。无法对BasicFiles 数据进行加密。SecureFiles 支持行业标准加密算法:3DES168、AES128、AES192(默认)和AES256。加密是高级安全选项的一部分。
注:必须将COMPATIBLE 初始化参数设置为11.0.0.0.0 或更高,才能使用SecureFiles。在11.1.0.0.0 兼容性下BasicFiles(以前的LOB)格式仍然受支持。设置11.0.0.0.0 后不会出现功能降低。
Oracle SecureFiles 提供了下列高级功能:

(1) 智能LOB 压缩

(2) 取消重复

(3) 透明加密
1.5 SecureFiles:存储选项
MAXSIZE 是新的存储子句,用于控制SecureFiles 的物理存储属性。MAXSIZE 指定与存储子句级别相关的最大段大小。
RETENTION 指定SecureFiles 的以下项:
(1) MAX 在达到段MAXSIZE 后重新使用旧版本。

(2) MIN 在指定的最短时间内保留旧版本。

(3) AUTO 是默认设置,主要对空间和时间进行折中使之达到平衡。这是自动确定的。

(4) NONE 尽可能重用旧版本。

使用ALTER TABLE 语句更改RETENTION 仅影响该语句执行后创建的空间。

对于SecureFiles,不再需要指定CHUNK、PCTVERSION、FREEPOOLS、FREELISTS 和FREELIST GROUPS。为了与现有脚本相兼容,将对这些子句进行分析但不解释它们。
1.6 创建SecureFiles
可使用CREATE TABLE 语句中的存储关键字SECUREFILE 创建带有LOB 列的SecureFiles。早期数据库版本中的LOB 实施现在被称为BasicFiles。将LOB 列添加到表时,可以指定是将其创建为SecureFiles 还是BasicFiles。如果没有指定存储类型,LOB 将创建为BasicFiles以确保向后兼容性。

CREATE TABLE func_spec(

id number, doc CLOBENCRYPT USING 'AES128' )

LOB(doc) STORE ASSECUREFILE

(DEDUPLICATE LOB CACHE NOLOGGING);

上面的SQL,创建了一个名为FUNC_SPEC的表,用于将文档存储为SecureFiles。在该示例中指定不希望存储LOB 的重复内容、读取时将高速缓存LOB,并且对LOB 执行更新时不生成还原。此外,还指定将使用AES128 加密算法对存储在doc 列中的文档进行加密。与DEDUPLICATE 相反,KEEP_DUPLICATES 可用在ALTER语句中。
CREATE TABLE test_spec (
id number, doc CLOB)
LOB(doc) STORE AS SECUREFILE
(COMPRESS HIGH KEEP_DUPLICATES CACHENOLOGGING);
上面的SQL,创建一个名为TEST_SPEC的表,用于将文档存储为SecureFiles。对于此表,可以存储重复内容、LOB 将以压缩格式存储,并且将高速缓存LOB 而不进行记录。HIGH 压缩设置需要进行更多的工作,但可提供更有效的数据压缩。默认压缩是MEDIUM。压缩算法在服务器端实施,允许对LOB 数据进行随机读取和写入,可以通过ALTER 语句对其进行更改。
CREATE TABLE design_spec (id number, docCLOB)
LOB(doc) STORE AS SECUREFILE (ENCRYPT);
CREATE TABLE design_spec (id number,
doc CLOB ENCRYPT)
LOB(doc) STORE AS SECUREFILE;
上面2段代码都结果相同:使用默认的AES192加密创建具有SecureFilesLOB 列的表
1.7 共享I/O池

为了支持共享内存(与程序全局区(PGA)相对)的大型I/O,OracleDatabase 11g 中新增了共享I/O 池内存组件,用于进行直接路径访问。这种情况仅适用于将SecureFiles 创建为NOCACHE 时(默认)。共享I/O 池默认大小为零,仅当存在SecureFiles NOCACHE 工作量时,系统才会将其大小增加到高速缓存的4%。由于这是共享资源,因此可由大型并发SecureFiles 工作量使用。与其它池(如大型池或共享池)不同,用户进程不会生成ORA-04031错误,但在释放更多共享I/O 池缓冲区之前会临时退回到PGA。
LOB 高速缓存是SecureFiles 体系结构中的新组件,通过收集和批处理数据以及重叠网络和磁盘I/O改进了LOB 访问性能。LOB高速缓存从缓冲区高速缓存(常规缓冲区或共享I/O 池的内存)借用内存。由于从缓冲区高速缓存借用的内存实质上适合于执行数据库I/O,并且适合在I/O 完成后回退到该缓冲区高速缓存,因此可以避免不必要的内存复制。
在多实例Oracle RealApplication Clusters 中,LOB 高速缓存为每个已访问的LOB 保留一个锁定
1.8 更改SecureFiles
使用DEDUPLICATE 选项,可以指定在LOB 列的两行或多行中相同的LOB 数据共享同一数据块。KEEP_DUPLICATES 与此相反。Oracle使用安全的散列索引检测重复,并且将具有相同内容的LOB 合并到一个副本中,从而降低存储空间并简化存储管理。LOB 关键字是可选的,它可以使语法变得更清楚。
COMPRESS 或NOCOMPRESS 关键字分别启用或禁用LOB 压缩。新的压缩设置会更改LOB 段中的所有LOB。
ENCRYPT 或DECRYPT关键字可使用透明数据加密(TDE) 打开或关闭LOB 加密。新设置会更改LOB 段中的所有LOB。可将LOB 段更改为仅启用或仅禁用LOB 加密。也就是说,ALTER 不能用于更新加密算法或加密密钥。可使用ALTER TABLE REKEY 语法更新加密算法或加密密钥。结合使用其它选项,在块级别执行加密可以提高性能(可能为最小的加密量)。
相关示例:
ALTER TABLE t1
MODIFY LOB(a) ( KEEP_DUPLICATES );
ALTER TABLE t1
MODIFY LOB(a) ( DEDUPLICATE LOB );
ALTER TABLE t1
MODIFY PARTITION p1 LOB(a) ( DEDUPLICATELOB );
ALTER TABLE t1
MODIFY LOB(a) ( NOCOMPRESS );
ALTER TABLE t1
MODIFY LOB(a) (COMPRESS HIGH);
ALTER TABLE t1
MODIFY PARTITION p1 LOB(a) ( COMPRESS HIGH);

ALTER TABLE t1 MODIFY

( a CLOB ENCRYPT USING '3DES168');

ALTER TABLE t1 MODIFY PARTITION p1

( LOB(a) ( ENCRYPT );

ALTER TABLE t1 MODIFY

( a CLOB ENCRYPT IDENTIFIED BY ghYtp);

1.9 访问SecureFiles 元数据

DBMS_LOB 程序包:LOB 继承取消重复、加密和压缩的LOB 列设置,也可使用LOB 定位器API 在每个LOB 级别上进行配置。但是不能使用LONG API 配置这些LOB 设置。

必须为这些功能使用以下DBMS_LOB 程序包附加函数:

(1) DBMS_LOB.GETOPTIONS:可使用此函数获得设置。返回与基于选项类型的预定义常量相对应的整数。

(2) DBMS_LOB.SETOPTIONS:此过程设置功能并允许按LOB 设置这些功能,从而覆盖默认的LOB 设置。这需要往返服务器以使更改变成永久更改。

DBMS_SPACE.SPACE_USAGE:使现有SPACE_USAGE 过程超载,以返回有关LOB 空间使用情况的信息。它返回LOB 段中所有LOB 使用的块中的磁盘空间量。该过程仅可对使用ASSM 创建的表空间使用,并且不将属于BasicFiles 的LOB 块视为已使用的空间。

1.10 迁移到SecureFiles

使用LOB 接口超集,可轻松从BasicFile LOB 进行迁移。迁移到SecureFiles 有两种建议方法:分区交换和联机重新定义。

分区交换:

(1) 需要与表中最大分区相等的额外空间

(2) 可在交换期间维护索引

(3) 可将工作量分散到多个较小的维护窗口

(4) 要求表或分区脱机以执行交换

联机重新定义(建议做法)

(1) 不要求表或分区脱机

(2) 可并行进行

(3) 要求额外存储空间等于整个表,并且所有LOB 段均可用

(4) 要求重建所有全局索引

这些解决方案通常意味着使用输入LOB列中的数据所用磁盘空间两倍的空间。但是,使用分区和按分区执行这些操作有助于降低所需的磁盘空间。

1.11 SecureFiles 监视

为了显示SecureFiles 的使用情况,已对下列视图进行了修改:

(1) *_SEGMENTS

(2) *_LOBS

(3) *_LOB_PARTITIONS

(4) *_PART_LOBS

SQL> SELECT segment_name, segment_type,segment_subtype

2 FROM dba_segments

3 WHERE tablespace_name = 'SECF_TBS2'

4 AND segment_type = 'LOBSEGMENT'

5 /

SEGMENT_NAME SEGMENT_TYPE SEGMENT_SU

---------------------------------------------- ----------

SYS_LOB0000071583C00004$$ LOBSEGMENTSECUREFILE

二.示例

2.1 修改DB_SECUREFILE参数

在1.3 小节提到这个参数,用来控制SecureFiles的使用。具体可设的参数参考1.3节。

启用SecureFile功能,数据的compatible 参数必须大于11.0.0.0. db_SecureFile 参数是个动态参数,我们可以直接修改,而不用重启实例。

[oracle@dave admin]$ ora paramdb_securefile

Session altered.

NAME ISDEFAULT SESMO SYSMOD VALUE

---------------- --------- ----- -------------------------------------------------

db_securefile TRUE TRUE IMMEDIATEPERMITTED

[oracle@dave admin]$ ora param compatible

Session altered.

NAME ISDEFAULT SESMO SYSMOD VALUE

--------------- --------- ----- -------------------------------------------------

compatible FALSE FALSE FALSE 11.2.0.0.0

SQL> alter system setdb_securefile='FORCE';

System altered.

SQL> !ora param db_securefile

Session altered.

NAME ISDEFAULT SESMO SYSMOD VALUE

------------------ --------- -------------- -------------

db_securefile TRUE TRUE IMMEDIATE FORCE

SQL> alter system setdb_securefile='PERMITTED';

System altered.

SQL> !ora param db_securefile

Session altered.

NAME ISDEFAULT SESMO SYSMOD VALUE

------------------ --------- -------------- --------------

db_securefile TRUE TRUE IMMEDIATE PERMITTED

2.2 创建 SecureFile LOBs

完整语法参考:

http://docs.oracle.com/cd/B28359_01/appdev.111/b28393/adlob_smart.htm

2.2.1 基本类型

SQL> CREATE TABLE bf_tab (

2 id NUMBER,

3 clob_data CLOB

4 )

5 LOB(clob_data) STORE AS BASICFILE;

Table created.

SQL> INSERT INTO bf_tab VALUES (1, 'MyCLOB data');

1 row created.

SQL> COMMIT;

Commit complete.

SQL> CREATE TABLE sf_tab (

2 id NUMBER,

3 clob_data CLOB

4 )

5 LOB(clob_data) STORE ASSECUREFILE;

CREATE TABLE sf_tab (
*
ERROR at line 1:
ORA-43853: SECUREFILElobs cannot be used in non-ASSM tablespace "SYSTEM"
--这里报错,创建securefile,必须是ASSM表空间。
SQL> selectTABLESPACE_NAME,SEGMENT_SPACE_MANAGEMENT from dba_tablespaces;
TABLESPACE_NAME SEGMEN

-------------------- ------

SYSTEM MANUAL

SYSAUX AUTO

UNDOTBS1 MANUAL

TEMP MANUAL

USERS AUTO

EXAMPLE AUTO

DAVE AUTO
7 rows selected.
SQL> CREATE TABLE sf_tab (

2 id NUMBER,

3 clob_data CLOB

4 )

5 LOB(clob_data) STORE ASSECUREFILE tablespace dave;
Table created.
SQL> INSERT INTO sf_tab VALUES (1, 'MyCLOB data');
1 row created.
SQL> commit;
Commit complete.
2.2.2 LOB Deduplication 重复值
LOB 重复值相关的2个选项:
(1)DEDUPLICATE:不允许出现重复值。

(2)KEEP_DUPLICATES: 允许出现重复值。
SQL> create user dave identified by"dave" default tablespace dave temporary tablespace temp;
User created.
SQL> grant connect,resource to dave;
Grant succeeded.
SQL> conn dave/dave;
Connected.
SQL> CREATE TABLE keep_duplicates_tab (

2 id NUMBER,

3 clob_data CLOB

4 )

5 LOB(clob_data) STORE ASSECUREFILE keepdup_lob(

6 KEEP_DUPLICATES

7 );
Table created.
SQL> CREATE TABLE deduplicate_tab (

2 id NUMBER,

3 clob_data CLOB

4 )

5 LOB(clob_data) STORE ASSECUREFILE dedup_lob (

6 DEDUPLICATE

7 );
Table created.
SQL> DECLARE
2 l_clob CLOB := RPAD('X',10000, 'X');

3 BEGIN

4 FOR i IN 1 .. 1000 LOOP

5 INSERT INTOkeep_duplicates_tab VALUES (i, l_clob);

6 END LOOP;

7 COMMIT;

8

9 FOR i IN 1 .. 1000 LOOP

10 INSERT INTO deduplicate_tab VALUES (i, l_clob);

11 END LOOP;

12 COMMIT;

13 END;

14 /
PL/SQL procedure successfully completed.
SQL> EXECDBMS_STATS.gather_table_stats(USER, 'keep_duplicates_tab');
PL/SQL procedure successfully completed.
SQL> EXECDBMS_STATS.gather_table_stats(USER, 'deduplicate_tab');
PL/SQL procedure successfully completed.
SQL> COLUMN segment_name FORMAT A30

SQL> SELECT segment_name, bytes

2 FROM user_segments

3 WHERE segment_name IN ('KEEPDUP_LOB', 'DEDUP_LOB');

SEGMENT_NAME BYTES

------------------------------ ----------

DEDUP_LOB 1179648

KEEPDUP_LOB 28442624

2 rows selected.
SQL>
允许重复值的情况下,占用的空间要大很多。我们可以使用alter table 命令来将deplicates改成keep_duplicates:
SQL> ALTER TABLE deduplicate_tab MODIFYLOB(clob_data) (

 KEEP_DUPLICATES

);
Table altered.
SQL> EXECDBMS_STATS.gather_table_stats(USER, 'deduplicate_tab');
PL/SQL procedure successfully completed.
SQL> COLUMN segment_name FORMAT A30
SQL> SELECT segment_name, bytes
FROM user_segments

wHERE segment_name IN ('KEEPDUP_LOB', 'DEDUP_LOB');

SEGMENT_NAME BYTES
------------------------------ ----------
DEDUP_LOB 25296896
KEEPDUP_LOB 28442624
SQL>
2.2.3 LOB Compression 压缩
SecureFIles的COMPRESS 选项允许在表或者分区级别进行压缩。 压缩的级别也分medium 和 high。

默认使用medium。 压缩会消耗一些资源,所以如果使用high 的压缩,那么可能会影响系统的性能。 SecureFiles的压缩对表的压缩是没有影响的。
SQL> CREATE TABLE nocompress_tab (

 id         NUMBER,

 clob_data  CLOB

)

LOB(clob_data) STORE AS SECUREFILEnocompress_lob(

 NOCOMPRESS

);

Table created.

SQL> CREATE TABLE compress_tab (

id         NUMBER,

clob_data  CLOB

)

LOB(clob_data) STORE ASSECUREFILE compress_lob (

 COMPRESS HIGH

);

Table created.

SQL> DECLARE

l_clob CLOB := RPAD('X',10000, 'X');

BEGIN

 FOR i IN 1 .. 1000 LOOP

   INSERT INTO nocompress_tabVALUES (i, l_clob);

 END LOOP;

 COMMIT;

FOR i IN 1 .. 1000 LOOP

  INSERT INTO compress_tab VALUES (i, l_clob);

END LOOP;

COMMIT;

END;

/

PL/SQL procedure successfully completed.
SQL> EXECDBMS_STATS.gather_table_stats(USER, 'nocompress_tab');
PL/SQL procedure successfully completed.
SQL> EXEC DBMS_STATS.gather_table_stats(USER,'compress_tab');
PL/SQL procedure successfully completed.

SQL> COLUMN segment_name FORMAT A30

SQL> SELECT segment_name, bytes

2 FROM user_segments

3 WHERE segment_name IN ('COMPRESS_LOB','NOCOMPRESS_LOB');

SEGMENT_NAME BYTES

------------------------------ ----------

COMPRESS_LOB 131072

NOCOMPRESS_LOB 28442624

SQL>

--使用压缩后,使用空间小很多。

将表compress_tab从压缩改成非压缩:

SQL> ALTER TABLE compress_tab MODIFY LOB(clob_data)(

2 NOCOMPRESS

3 );

Table altered.

SQL> EXECDBMS_STATS.gather_table_stats(USER, 'compress_tab');

PL/SQL procedure successfully completed.

SQL> COLUMN segment_name FORMAT A30

SQL> SELECT segment_name, bytes

2 FROM user_segments

3 WHERE segment_name IN ('COMPRESS_LOB','NOCOMPRESS_LOB');

SEGMENT_NAME BYTES

------------------------------ ----------

COMPRESS_LOB 26345472

NOCOMPRESS_LOB 28442624

--压缩的空间又释放出来了。
2.2.4 LOB Encryption 加密

SecureFileLobs 的加密依赖wallet 或者HardwareSecurity Model (HSM)来保存encryption key。 所以在创建加密的SecureFile之前,必须先创建并打开一个wallet。

2.2.4.1 创建wallet

在sqlnet.ora 文件里添加: ENCRYPTION_WALLET_LOCATION 和WALLET_LOCATION参数。

默认位置是:$ORACLE_BASE/admin/$ORACLE_SID/wallet。

--指定ORACLE WALLET的位置,这里使用ORACLE_HOME/network/admin,在sqlnet.ora里添加如下内容:

WALLET_LOCATION =

(SOURCE =

(METHOD = FILE)

(METHOD_DATA =

  (DIRECTORY = /u01/app/oracle/product/11.2.0/db_1/network/admin)

)

)

ENCRYPTION_WALLET_LOCATION =

(SOURCE =

(METHOD = FILE)

(METHOD_DATA =

  (DIRECTORY = /u01/app/oracle/admin/dave/encryption_wallet)

)

)

SQLNET.WALLET_OVERRIDE = TRUE

SSL_CLIENT_AUTHENTICATION = FALSE

SSL_VERSION = 0

--添加完之后,重启listener,使参数生效。

--创建wallet:包括设置密码、生成信任文件、并启动wallet

CONN / AS SYSDBA

-- 10g version

ALTER SYSTEM SET ENCRYPTION KEYAUTHENTICATED BY "myPassword";

-- 11g version

ALTER SYSTEM SET ENCRYPTIONKEY IDENTIFIED BY "myPassword";

当实例重启后或者wallet被关闭后,必须重新open wallets,这样才能保护被加密的列:

-- 10g version

ALTER SYSTEM SET ENCRYPTION WALLET OPENAUTHENTICATED BY "myPassword";

-- 11g version

ALTER SYSTEM SET ENCRYPTION WALLET OPENIDENTIFIED BY "myPassword";

ALTER SYSTEM SET ENCRYPTION WALLET CLOSE;

2.2.4.2 示例

SecureFile的ENCRYPT  在block-level上对LOBS的内容进行加密。可以使用USING 选项来指定使用哪种加密算法:3DES168, AES128, AES192,AES256,默认使用AES192进行加密。

当对SecureFile 进行加密后,NO SALT 选项不可用。加密是基于列来进行,如果是分区表,那么会影响所有的分区。

DECRYPT选项用来进行解密操作。 具体示例如下:

SQL> conn dave/dave;

Connected.

SQL> CREATE TABLE encrypt_tab (

2 id NUMBER,

3 clob_data CLOB

4 )

5 LOB(clob_data) STORE ASSECUREFILE encrypt_lob(

6 ENCRYPT USING 'AES256'

7 );
Table created.
--可以使用使用alert 来对已经存在的列进行加密或者解密操作,如果要更换加密算法的类型,必须使用REKEY 选项:
SQL> ALTER TABLE encrypt_tab MODIFY (

2 clob_data CLOB DECRYPT

3 );
Table altered.
SQL> ALTER TABLE encrypt_tab MODIFY (

2 clob_data CLOB ENCRYPT USING '3DES168'

3 );
Table altered.
SQL> ALTER TABLE encrypt_tab REKEY USING'AES192';

Table altered.

注意:

Exp/imp 工具不支持Encryption,所以要对加密的列进行传输,必须使用数据泵:expdp/impdp.

2.2.5 LOB Cache and Logging

BasicFile和SecureFile LOBs 都可以进行caching 和logging的设置,相关说明如下:

caching 值:

(1) CACHE - LOB data is placed in the buffer cache.

(2) CACHE READS - LOB data is only placed in the buffer cacheduring read operations, not write operations.

(3) NOCACHE - LOB data is notplaced in the buffer cache. This is the default optionfor BasicFile and SecureFile LOBs.

Basic的 logging 值:

(1) LOGGING - LOB creation andchanges generate full redo. This is the defaultsetting.

(2) NOLOGGING - The operations are not logged in the redo logs andare therefore not recoverable. This is useful during initial creation andduring large loads that can be replayed in the event of failure.

对与SecureFileLOBs多一个FILESYSTEM_LIKE_LOGGING选项,如果指定该选项,那么只对metadata 进行logging。

注意:

Cache 选项就意味着进行logging,所以如果指定了Cache,就不能指定logging 或者FILESYSTEM_LIKE_LOGGING.

相关示例:

CREATE TABLE caching_and_logging_tab (

id NUMBER,

clob_data CLOB

)

LOB(clob_data) STORE AS SECUREFILE(

NOCACHE

FILESYSTEM_LIKE_LOGGING

);

ALTER TABLE caching_and_logging_tab MODIFYLOB(clob_data) (

CACHE

);

2.2.6 使用PL/SQL APIs 对LOBs 属性进行查看与修改

2.2.6.1 DBMS_LOB package

DBMS_LOB 包可以查看BasicFile和SecureFile LOBs。 SETOPTIONS 过程和GETOPTIONS 函数查看compression, encryption anddeduplication 选项的修改。

CREATE TABLE securefile_tab (

id NUMBER,

clob_data CLOB

)

LOB(clob_data) STORE AS SECUREFILEsecurefile_lob(

encrypt

compress

);

INSERT INTO securefile_tab VALUES (1, 'Dave');

INSERT INTO securefile_tab VALUES (2, 'Oracle');

COMMIT;

SET SERVEROUTPUT ON

DECLARE

l_clob CLOB;

BEGIN

SELECT clob_data

INTO l_clob

FROM securefile_tab

WHERE id = 1

FORUPDATE;

DBMS_OUTPUT.put_line('Compression : ' || DBMS_LOB.getoptions(l_clob, DBMS_LOB.opt_compress));

DBMS_OUTPUT.put_line('Encryption : ' || DBMS_LOB.getoptions(l_clob, DBMS_LOB.opt_encrypt));

DBMS_OUTPUT.put_line('Deduplication: ' || DBMS_LOB.getoptions(l_clob,DBMS_LOB.opt_deduplicate));

ROLLBACK;

END;

/

这里返回:

Encryption : 2

Deduplication: 0

2.2.6.2 DBMS_SPACE package

DBMS_SPACE包的SPACE_USAGE过程可以查看LOBs 占用磁盘空间信息。 该过程只适用与ASSM 表空间。

SET SERVEROUTPUT ON

DECLARE

l_segment_size_blocks NUMBER;

l_segment_size_bytes NUMBER;

l_used_blocks NUMBER;

l_used_bytes NUMBER;

l_expired_blocks NUMBER;

l_expired_bytes NUMBER;

l_unexpired_blocks NUMBER;

l_unexpired_bytes NUMBER;

BEGIN

DBMS_SPACE.SPACE_USAGE(

segment_owner         => 'TEST',

segment_name =>'SECUREFILE_LOB',

segment_type => 'LOB',

segment_size_blocks =>l_segment_size_blocks,

segment_size_bytes =>l_segment_size_bytes,

used_blocks =>l_used_blocks,

used_bytes =>l_used_bytes,

expired_blocks =>l_expired_blocks,

expired_bytes =>l_expired_bytes,

unexpired_blocks =>l_unexpired_blocks,

unexpired_bytes =>l_unexpired_bytes);

DBMS_OUTPUT.put_line('segment_size_blocks:' || l_segment_size_blocks);

DBMS_OUTPUT.put_line('segment_size_bytes :' || l_segment_size_bytes);

DBMS_OUTPUT.put_line('used_blocks :' || l_used_blocks);

DBMS_OUTPUT.put_line('used_bytes :' || l_used_bytes);

DBMS_OUTPUT.put_line('expired_blocks :' || l_expired_blocks);

DBMS_OUTPUT.put_line('expired_bytes :' || l_expired_bytes);

DBMS_OUTPUT.put_line('unexpired_blocks :' || l_unexpired_blocks);

DBMS_OUTPUT.put_line('unexpired_bytes :' || l_unexpired_bytes);

END;

/
这个和我们的show_space 脚本是一样的。
OracleShow_space 过程 使用示例 与 注释
http://www.cndba.cn/Dave/article/410
2.2.7 Migrating to SecureFiles 从BasicFile迁移到SecureFiles
将列从BasicFile LOB迁移到SecureFilesLOB,可以使用如下方法:

(1) CREATE TABLE ... AS SELECT ...

(2) INSERT INTO ... SELECT ...

(3) Online tableredefintion.

(4) Export/Import

(5) Create a new column, update the new column with the values in theoriginal column, then drop the old column.

(6) Create a new column, update the new column with the values in theoriginal column, rename the table and create a view with the original name thatonly references the new column.
除了export/import 的方法,其他的方法都需要考虑转换LOB需要的磁盘空间问题。

Oracle 的Streams 不支持SecureFIles,所以不能使用Streams来迁移LOBs。
在1.10 小节里,也说明,在不考虑空间的情况下,推荐使用表的在线重定义来进行操作。对于在线重定义,我们在表转分区表的时候也用过。 参考如下连接的2.3 小节:使用在线重定义:DBMS_REDEFINITION。

为啥SecureFile类型的LOB要比以前的LOB性能要好很多,是不是存储结构上发生了什么变化,看了些资料,现在整理出来算是回答他的问题了。

11g以前的LOB类型的实现方式可以参考前一段写的一篇博文《CLOB的物理存储结构及语言编码详解》。从11g开始,Oracle提供了一种新的LOB存储方式叫SecureFile,以前旧有的LOB存储方式就叫BasicFile了。Oracle宣称,“SecureFile不仅是新一代 LOB,它们还为 LOB 带来了更多的价值,尤其是以前只能在文件系统领域中获得的特性。SecureFile可以进行加密以确保安全性,可以进行重复消除和压缩以提高存储效率,可以进行缓存(或不进行缓存)以加快访问(或节省缓冲池空间),可以按多个级别记录以减少崩溃后的平均恢复时间。引入 SecureFile 后,您可以在数据库中存储更多的非结构化文档,而不会导致过多的开销,也不会失去 OS 文件系统提供的任何重要功能。

简单来说就三条:

一、提供了压缩、重复消除、加密等新功能

二、比以前的LOB的性能提高很多

三、易用性(无需设置CHUNK、PCTVERSION、FREELISTS、FREELIST GROUPS、FREEPOOLS参数)

注意:压缩需要Oracle Advanced Compression Option,加密需要Oracle Advanced Security Option,这两个option都是单独购买的,没有包括在Enterprise Edition里面。

  1. 使用SecureFile

想要使用SecureFile LOB很简单,只需指定STORE AS SECUREFILE子句就行了(测试环境为11gR2):

CREATE TABLE t11 (id number,c1 CLOB) LOB (c1) STORE AS SECUREFILE;

Securefile列标明了是否为SecureFile类型的LOB:

SELECT table_name,segment_name,index_name,securefile FROM dba_lobs WHERE table_name='T11';
TABLE_NAME SEGMENT_NAME INDEX_NAME SECUREFIL
---------- ------------------------------ ------------------------------ ---------
T11 SYS_LOB0000069030C00001$$ SYS_IL0000069030C00001$$ YES

使用Securefile LOB的表也是自动生成LOB segment和LOB index的。但是此时LOB index只有在使用重复消除功能时才会使用,在其他情况下均不会使用。要注意,Securefile LOB只能在ASSM的表空间(自动管理的表空间)里创建,不过既然从9i起ASSM表空间就是默认设置了,一般这里不会有多大问题。还要多说一句,只是要求SecureLOB所在的LOB列数据需要存放在ASSM表空间中,而包含LOB列的那个表,你还是可以放在手动管理的表空间中。

想使用SecureFile LOB,对数据库的参数DB_SECUREFILE设置也有一定的要求:

PERMITTED:数据库的默认参数。指定SecureFile时创建SecureFile类型的LOB;未指定时,或显式指定BasicFile时,创建BasicFile类型的LOB。

FORCE:无论是否指定SecureFile,强制创建SecureFile类型的LOB。在手动管理的表空间上创建LOB时,无论STORAGE子句是否指定SecureFile,均报ORA-43853错。

ALWAYS:无论是否指定SecureFile,强制创建SecureFile类型的LOB。在手动管理的表空间上创建LOB时,若 STORAGE子句未显式指定LOB类型,创建为BasicFile类型的LOB;若STORAGE子句显式指定SecureFile类型,则也报 ORA-43853错。

NEVER:无论是否指定SecureFile,强制创建BasicFile类型的LOB。指定SecureFile类型特有的功能如压缩,加密,重复消除时,报ORA-43854错

IGNORE:无论是否指定SecureFile,强制创建BasicFile类型的LOB。忽略SecureFile类型特有的功能,创建BasicFile类型的LOB。

BasicFile和SecureFile的架构比较
可变Chunk

首先介绍一下SecureFile中的可变Chunk。大家都知道在BasicFile的LOB中,Chunk的大小是一定的,最小跟DB Block的大小一样,最大为32KB,这存在一些问题。比如chunk比LOB的数据小很多的情况下,访问LOB就会产生很多IO,而chunk比 LOB的数据大很多的情况下,又会产生对存储空间的浪费。而在SecureFile中,chunk的size是可变的,由Oracle自动动态分配,最小跟DB Block的大小一样,最大为64MB。这样在存储较小的LOB时,使用比较小的chunk;在存储比较大的LOB时,会使用比较大的chunk。注意不是说一个LOB就放在一个chunk里,而是oracle根据LOB data的数据大小会自动决定chunk数和chunk的size,具体可以看下面“SecureFile的物理存储结构”一节的实验结果。
3.2. LOB index

在LOB数据的存储方式上,两种LOB也有很大的区别。关于BasicFile的存储方式,在《CLOB的物理存储结构及语言编码详解》一文中有详细的介绍,大概就是表中的LOB字段只存储LOB locator,指向LOB index,LOB index再指向LOB segment里实际的LOB数据。不难看出,这里增加了一个LOB index的结构,那么不可避免的,LOB index就有可能产生竞争,成为瓶颈。在SecureFile中,LOB index只有在使用重复消除功能时才会使用(关于这个结论的验证方法,在CLOB那篇文章中有记载,这里不再赘述了)。简而言之,SecureFile中只要不使用重复消除功能就没LOB index什么事,自然性能就上去了。
BasicFile Col1 LOB col —-> LOB index —-> LOB data
SecureFile Col1 LOB col —————-> LOB data
3.3. 空闲空间搜索

在BasicFile里,关于有空间的使用情况的信息是保存在LOB index和LOB segment里的。在INSERT或UPDATE操作LOB segment时,以下面的顺序来搜索空闲空间:

  1. 在LOG segment的管理区搜索空闲空间,如果没有,转下一步
  2. 访问LOB index,把可以释放的空间(如已经commit的transaction使用的UNDO)释放掉,并更新索引entry。如果不存在这种可以释放的空间,转下一步
  3. 将HWM升高,扩大LOB segment,使用新分配的空间

由此可见,BasicFile的LOB在搜索空闲空间时,可能会去扫描LOB index。因此LOB index的竞争,或者在LOB数据很多的情况下,搜索LOB index的空闲空间这个操作本身都会造成时间上的花费。

对于空闲空间的管理,SecureFile将其放入了shared pool,这比BasicFile空闲空篇博文《CLOB的物理存储结构及语言编码详解》。从11g开始,Oracle提供了一种新的LOB存储方式叫SecureFile,以前旧有的LOB存储方式就叫BasicFile了。Oracle宣称,“SecureFile不仅是新一代 LOB,它们还为 LOB 带来了更多的价值,尤其是以前只能在文件系统领域中获得的特性。SecureFile可以进行加密以确保安全性,可以进行重复消除和压缩以提高存储效率,可以进行缓存(或不进行缓存)以加快访问(或节省缓冲池空间),可以按多个级别记录以减少崩溃后的平均恢复时间。引入 SecureFile 后,您可以在数据库中存储更多的非结构化文档,而不会导致过多的开销,也不会失去 OS 文件系统提供的任何重要功能。”

简单来说就三条:

一、提供了压缩、重复消除、加密等新功能

二、比以前的LOB的性能提高很多

三、易用性(无需设置CHUNK、PCTVERSION、FREELISTS、FREELIST GROUPS、FREEPOOLS参数)

注意:压缩需要Oracle Advanced Compression Option,加密需要Oracle Advanced Security Option,这两个option都是单独购买的,没有包括在Enterprise Edition里面。

  1. 使用SecureFile

想要使用SecureFile LOB很简单,只需指定STORE AS SECUREFILE子句就行了(测试环境为11gR2):

CREATE TABLE tst.t11 (id number,c1 CLOB) LOB (c1) STORE AS SECUREFILE;

Securefile列标明了是否为SecureFile类型的LOB:

SELECT table_name,segment_name,index_name,securefile FROM dba_lobs WHERE table_name='T11';
TABLE_NAME SEGMENT_NAME INDEX_NAME SECUREFIL
---------- ------------------------------ ------------------------------ ---------
T11 SYS_LOB0000069030C00001$$ SYS_IL0000069030C00001$$ YES

使用Securefile LOB的表也是自动生成LOB segment和LOB index的。但是此时LOB index只有在使用重复消除功能时才会使用,在其他情况下均不会使用。要注意,Securefile LOB只能在ASSM的表空间(自动管理的表空间)里创建,不过既然从9i起ASSM表空间就是默认设置了,一般这里不会有多大问题。还要多说一句,只是要求SecureLOB所在的LOB列数据需要存放在ASSM表空间中,而包含LOB列的那个表,你还是可以放在手动管理的表空间中。

想使用SecureFile LOB,对数据库的参数DB_SECUREFILE设置也有一定的要求:

PERMITTED:数据库的默认参数。指定SecureFile时创建SecureFile类型的LOB;未指定时,或显式指定BasicFile时,创建BasicFile类型的LOB。

FORCE:无论是否指定SecureFile,强制创建SecureFile类型的LOB。在手动管理的表空间上创建LOB时,无论STORAGE子句是否指定SecureFile,均报ORA-43853错。

ALWAYS:无论是否指定SecureFile,强制创建SecureFile类型的LOB。在手动管理的表空间上创建LOB时,若 STORAGE子句未显式指定LOB类型,创建为BasicFile类型的LOB;若STORAGE子句显式指定SecureFile类型,则也报 ORA-43853错。

NEVER:无论是否指定SecureFile,强制创建BasicFile类型的LOB。指定SecureFile类型特有的功能如压缩,加密,重复消除时,报ORA-43854错。

IGNORE:无论是否指定SecureFile,强制创建BasicFile类型的LOB。忽略SecureFile类型特有的功能,创建BasicFile类型的LOB。

  1. BasicFile和SecureFile的架构比较
    3.1. 可变Chunk

首先介绍一下SecureFile中的可变Chunk。大家都知道在BasicFile的LOB中,Chunk的大小是一定的,最小跟DB Block的大小一样,最大为32KB,这存在一些问题。比如chunk比LOB的数据小很多的情况下,访问LOB就会产生很多IO,而chunk比 LOB的数据大很多的情况下,又会产生对存储空间的浪费。而在SecureFile中,chunk的size是可变的,由Oracle自动动态分配,最小跟DB Block的大小一样,最大为64MB。这样在存储较小的LOB时,使用比较小的chunk;在存储比较大的LOB时,会使用比较大的chunk。注意不是说一个LOB就放在一个chunk里,而是oracle根据LOB data的数据大小会自动决定chunk数和chunk的size,具体可以看下面“SecureFile的物理存储结构”一节的实验结果。
3.2. LOB index

在LOB数据的存储方式上,两种LOB也有很大的区别。关于BasicFile的存储方式,在《CLOB的物理存储结构及语言编码详解》一文中有详细的介绍,大概就是表中的LOB字段只存储LOB locator,指向LOB index,LOB index再指向LOB segment里实际的LOB数据。不难看出,这里增加了一个LOB index的结构,那么不可避免的,LOB index就有可能产生竞争,成为瓶颈。在SecureFile中,LOB index只有在使用重复消除功能时才会使用(关于这个结论的验证方法,在CLOB那篇文章中有记载,这里不再赘述了)。简而言之,SecureFile中只要不使用重复消除功能就没LOB index什么事,自然性能就上去了。
BasicFile Col1 LOB col —-> LOB index —-> LOB data
SecureFile Col1 LOB col —————-> LOB data
3.3. 空闲空间搜索

在BasicFile里,关于有空间的使用情况的信息是保存在LOB index和LOB segment里的。在INSERT或UPDATE操作LOB segment时,以下面的顺序来搜索空闲空间:

  1. 在LOG segment的管理区搜索空闲空间,如果没有,转下一步
  2. 访问LOB index,把可以释放的空间(如已经commit的transaction使用的UNDO)释放掉,并更新索引entry。如果不存在这种可以释放的空间,转下一步
  3. 将HWM升高,扩大LOB segment,使用新分配的空间

由此可见,BasicFile的LOB在搜索空闲空间时,可能会去扫描LOB index。因此LOB index的竞争,或者在LOB数据很多的情况下,搜索LOB index的空闲空间这个操作本身都会造成时间上的花费。

对于空闲空间的管理,SecureFile将其放入了shared pool,这比BasicFile空闲空间管理的效率有了质的提高。 Shared Pool里的这个内存结构叫In-memory dispenser,它把空闲空间的信息cache在内存里,因此速度要比访问LOB index快了N个数量级。In-memory dispenser负责接受前台进程对于LOB空间的请求,并进行chunk的分配。

在In-memory dispenser中管理的空闲空间不是全部,而只是一部分而已,它的信息由后台进程SMCO/Wnnn来定期的更新。SMCO/Wnnn监视 SecureFile LOB segment的使用情况,根据需要保证空闲空间的供应。注意SMCO/Wnnn也负责普通的ASSM表空间的空间动态分配。

  1. SMCO进程(Space Management Coordinator)。负责前瞻式(Proactive)的空间分配,它动态产生slave进程Wnnn来完成实际的工作。
  2. Wnnn(SMCO Worker)每10分钟扫描一遍LOB segment的状态,根据需要把空chunk移动到In-memory dispenser中。如果这样空chunk还是不够,则扩大LOB segment。

此时在INSERT或UPDATE操作LOB segment时,以下面的顺序来搜索空闲空间:

  1. 前台进程向In-memory dispenser发出需要chunk的请求
  2. In-memory dispenser里的chunk信息里如果空chunk数量不足,或者空chunk的size不够时,在LOG segment的管理区搜索空闲空间,将空chunk的信息cache在In-memory dispenser里。如果搜索不到空闲空间,转下一步
  3. 将HWM升高,扩大LOB segment,使用新分配的空间
    3.4. STORAGE参数

跟BasicFile一样,SecureFile同样也有enable storage in row和disable storage in row的区别,在SecureFile的LOB里默认设置同样也是enable storage in row。LOB控制结构size加上LOB数据size一共未满4000字节时,enable storage in row的情况下就存储在源表的LOB列内,超出时就存放在LOB segment里;而disable storage in row的情况下则无论是否超过4000字节,LOB数据均存放在LOB segment里。

《CLOB的物理存储结构及语言编码详解》一文中提到过,enable storage in row的情况下源表的LOB列最多能存放3964字节;而在DB11gR1的SecureFile LOB中,变成了3740字节;DB11gR2时又变成了3952字节。均为引用的数据,具体区别尚未弄清。个人认为Size的变化都是因为LOB的控制信息发生了细微的变化。注意这里的size都是在未使用重复消除、加密、压缩选项的情况下得出的。

  1. SecureFile的物理存储结构

下面就是本文的重头戏了,SecureFile的LOB到底在物理上是怎么存储的。在Table的Segment里的LOB列中,存放着两个 layer:Locator Layer(20字节)和Inode Layer。Locator的内容和BasicFile里是一样的,也包括了控制信息和10字节的LOB ID。而Inode Layer包含了RCI Header和Inode部分,其中Inode部分包含了指向LOB segment的指针,或者在In-line存储的情况下包含实际的LOB 数据。RCI(LOB Row-Column Intersection)即表Segment里存储的LOB列的所有数据,RCI Header里存储的是SecureFile的LOB控制信息。具体的定义如下:

2字节的Inode Layer整个的size,即表Segment里LOB列中,Locator Layer之外的size。如果是in-line存储的话也包括LOB数据的size在内。

1字节的flag,具体含义如下

0×01 此LOB是有效LOB

0×02 此inode在Index中

0×04此inode是in-line的

0×08 in-line的数据是实际的LOB数据

0×10 此inode是临时lob的控制结构

0×40此LOB是SecureFile的LOB

比如我们dump出block这里是0×48,就说明这个LOB是SecureFile的LOB,而且是in-line存储的。

1字节的SecureFile的LOB的选项flag:0×1是启用重复消除,0×2是启用压缩,0×4是启用加密。下面举例说明:

上文里创建过T11表,T11表没指定storage in row选项,因此就是默认的enable storage in row。给T11表插入两条测试数据,一条是in-line方式存储的,一条是out-of-line方式存储的:

SELECT id,dbms_lob.getlength(c1) FROM tst.t11;
ID DBMS_LOB.GETLENGTH(C1)
---------- ----------------------
1 56
2 25583
ALTER databas FLUSH buffer_cache;
SELECT dbms_rowid.rowid_to_absolute_fno(rowid,'TST','T11') fno,
dbms_rowid.rowid_block_number(rowid) bno,id FROM tst.t11;
FNO BNO ID
---------- ---------- ----------
5 132 1
5 132 2
ALTER system dump datafile 5 block 132;
SELECT value FROM v$diag_info WHERE name='Default Trace File';

VALUE

/u01/app/oracle/diag/rdbms/dbeuc/dbeuc/trace/dbeuc_ora_25611.trc

我认为这里的定义应该跟BasicFile没有发生变化:2字节的LOB locator长度 (除这两个长度字节外)+ 2字节的LOB locator structure版本 + 4字节的FLAG + 2字节的字符集里字符的长度

我们看一下第一个chunk:

SELECT DBMS_UTILITY.data_block_address_block(TO_NUMBER('14033a2','xxxxxxxx'))
bno FROM dual;

BNO

13218

得到:

我们再看一下最后一个block:

SELECT DBMS_UTILITY.data_block_address_block(TO_NUMBER('1403314','xxxxxxxx'))
bno FROM dual;

BNO

13076

现在需要dump从13076开始的第6个即13081号block,得到:

… … …
hwm 2806
… … …

一共8060×6+2806=51166字节的LOB data,这与前面的结果是能相互印证的。

下面我们再来看disable storage in row的情况下SecureFile是如何存储的。

在这种情况下指向LOB data的指针可能有两种存储方式:

第一种:LOB data的size不算很大的情况下,在Table Segment里的LOB列中以chunk的初始RDBA + size的方式存储,一个chunk信息接着一个chunk信息;

第二种:LOB data的size很大的情况下,在Table Segment里的LOB列中存储LHB(Lob Header Block)的信息,在LHB中存放所有chunk及size的列表。

第一种跟上面的第二条数据存储方式差不多,就不再介绍了,下面我们看第二种情况:

CREATE TABLE tst.t12 (id number,c2 CLOB) LOB (c2) STORE AS SECUREFILE(disable storage IN row);
插入一条很大的LOB数据:
SELECT id,dbms_lob.getlength(c2) FROM tst.t12;

    ID DBMS_LOB.GETLENGTH(C2)

---------- ----------------------

     1               49498672

ALTER databas FLUSH buffer_cache;
SELECT dbms_rowid.rowid_to_absolute_fno(rowid,'TST','T12') fno,
dbms_rowid.rowid_block_number(rowid) bno,id FROM tst.t12;

   FNO        BNO         ID

---------- ---------- ----------

     5        173          1

ALTER system dump datafile 5 block 173;

现在来看一下Table Segment里存放LOB列的地方是什么信息:

我们把LHB给dump出来看看:

SELECT DBMS_UTILITY.data_block_address_block(TO_NUMBER(LTRIM('01403b81'),'xxxxxxxx'))
BNO FROM dual;

BNO

15233
ALTER system dump datafile 5 block 15233;

可以看到下面有chunk列表,以 block数 + RDBA的形式存储:

接下来对于LOB data所在的block的dump这里就不做了,方法跟上述的类似。

  1. 两种LOB性能测试比较
    上面说了这么多新的SecureFile的LOB怎么怎么好,怎么怎么牛,大家一定有疑问了,是不是我在这忽悠大家呢。下面就给大家看些干货,真实的测试数据。

首先介绍下LOB参数:
LOGGING:在CREATE/UPDATE/INSERT LOB数据时会写入REDO LOG文件。但NOLOGGING会Internally转换成FILESYSTEM_LIKE_LOGGING,而FILESYSTEM_LIKE_LOGGING会确保数据库CRASH完整恢复
NOLOGGING:在CREATE/UPDATE/INSERT LOB数据时不写入REDO LOG文件。
FILESYSTEM_LIKE_LOGGING:数据库只记录LOB的METADATA到REDO LOG
NOCACHE:LOB数据不CACHE在SGA
CACHE:LOB数据CACHE在SGA

结论已经很明显,新SecureFile格式的LOB性能相比较以前BasicFile有了巨大的提升,而且在最典型LOB的选项组合NOCACHE + LOGGING的情况下,性能提升的比例最大。

两种LOB的性能数据也可以参考这篇博文:
http://blog.sina.com.cn/s/blog_6058d7c10100nx26.html

他的测试结果如下,有的测试结果跟我的结果相比有一定的出入,可能是环境的问题,也可能是数据的问题(我是110MB的文本文件,他是5MB的文本文件),也可能是程序的问题(他用的java,我用的是PL/SQL)。另外他这篇文章里有关于SELECT(即READ)的性能数据,在NOCACHE + LOGGING的情况下,性能提升约三倍。

总结及附录
做个总结吧,我认为SecureFile的LOB之所以比BasicFile的LOB性能有提升,就是因为可变chunk、LOB index不再使用、空闲空间搜索放到了shared pool里这三大原因共同决定的,尤其是后两者,比起以前的BasicFile LOB,架构设计上有了飞跃。我们也能看出虽然Oracle数据库的发展不像以前那么革命性了,但是在很多方面,新版本的Oracle数据库还是取得了巨大的进步。

附录:
测试表(只写了一种,其他的选项组合类似):
create table tst.LOBTAB(ARTICLE_ID NUMBER PRIMARY KEY,ARTICLE_NAME VARCHAR2(50),
ARTICLE_DATA CLOB) tablespace data lob (ARTICLE_DATA)
store as SECUREFILE (tablespace DATA cache) LOGGING;

插入CLOB数据的存储过程insert_clob:
create or replace procedure tst.insert_clob (fromid in number,endid in number)
AS
i NUMBER;
V_LOB CLOB;
V_FILE BFILE := BFILENAME('HOME_DIR', 'lob.txt');
V_SOURCE NUMBER := 1;
V_DEST NUMBER := 1;
V_LANG NUMBER := 0;
V_WARN NUMBER;
BEGIN

for i in fromid..endid loop
V_SOURCE := 1;
V_DEST := 1;
INSERT INTO tst.LOBTAB VALUES (i, 'ABC'||to_char(i), 'TEST');
UPDATE tst.LOBTAB SET ARTICLE_DATA = EMPTY_CLOB where ARTICLE_ID=i RETURN ARTICLE_DATA INTO V_LOB;
DBMS_LOB.FILEOPEN(V_FILE);
DBMS_LOB.OPEN(V_LOB, DBMS_LOB.LOB_READWRITE);

DBMS_LOB.LOADCLOBFROMFILE(
V_LOB,
V_FILE,
DBMS_LOB.GETLENGTH(V_FILE),
V_DEST,
V_SOURCE,
0,
V_LANG,
V_WARN);

DBMS_LOB.CLOSE(V_LOB);
DBMS_LOB.FILECLOSEALL;
COMMIT;
end loop;
END;
/

计算CLOB的INSERT操作的时间差是使用以下的PL/SQL:
declare
a VARCHAR2(50);
b VARCHAR2(50);
begin
select to_char(systimestamp,'HH24:MI:SS.FF3') into a from dual;
TST.insert_clob(1,20);
select to_char(systimestamp,'HH24:MI:SS.FF3') into b from dual;
dbms_output.put_line(a);
dbms_output.put_line(b);
end;
/

总结: Oracle 11g 默认的clob是BasicFile方式的,现在Oracle重新提供一种clob字段的存储方式SecureFiles 管理clob字段,使用 SecureFiles 管理clob字段的存储方式expdp 导出比11g clob是BasicFile方式快了将近5倍,效果提升还是很明显的Oracle12C现在默认的就是SecureFiles 管理clob字段的方式,SecureFile比BasicFile(传统的LOB)无论是读还是写,Securefile性能远远超过BasicFile,呈倍数的提高。
Oracle官方参考文档地址:
http://www.oracle.com/technetwork/cn/articles/sql/11g-securefiles-098104-zhs.html
http://www.oracle.com/technetwork/database/features/secure-files/securefiles-160920.html

SecureFiles:新 LOB
了解如何使用新一代 LOB:SecureFiles。SecureFiles 集外部文件与数据库 LOB 方法的优点于一身,可以存储非结构化数据,允许加密、压缩、重复消除等。

参见系列目录

数据库驻留 BLOB 或操作系统文件
您在 Oracle 数据库中存储什么?通常,您会以关系格式存储数据以便映射到某些定义模式的类型,或者以客户姓名、帐户余额、状态代码等定义的数据类型存储数据。但是,以非结构化或半结构化形式存储信息的需求也日益增加。例如,照片、字处理文档、电子表格、XML 文件等等。这些类型的数据如何存储?

通常有两种方法:这些数据作为 LOB 字段(BLOB 用于存储二进制数据,CLOB 用于存储字符数据)存储在数据库中,或者通过引用存储在数据库中的文件存储在操作系统文件中。

每种方法都有优缺点。操作系统文件可以由操作系统和日志文件系统缓存以加速崩溃后的恢复。由于可进行压缩,因此操作系统文件占用的空间通常也比数据库中的数据要少。

还有一些工具可以智能地识别文件模式并消除重复从而提高存储效率;但是操作系统文件位于数据库外部,因此数据库属性不适用于它们。这些文件不进行备份,细粒度安全性不适用于它们,此类文件不是事务的一部分 — 因此 Oracle 数据库固有的读取一致性等概念不适用于它们。

如果能集两种方法的优点于一身会怎样?Oracle Database 11g 中的 SecureFiles 为您提供了答案。SecureFiles 是数据库中一个全新的基础架构,可提供最佳的数据库驻留 LOB 和操作系统文件性能。让我们看一看这种方案的实现方式。(顺便说明的是,传统 LOB 仍然以 BasicFiles 格式提供。)

实际示例
通过一个简单的示例来介绍 SecureFiles 概念或许是一种最佳方式。假设您要开发一个合同管理系统,在该系统中您希望将所有合同的副本都放在一个表中。扫描的文档通常是 PDF 文件而非文本。某些可能是 MS Word 文档,甚至是扫描的照片。这是 BLOB 的最佳使用案例,因为列必需能够支持二进制数据。

过去,在 Oracle Database 11g 推出之前,您可能会按照以下方式定义表:

create table contracts_basic
(

    contract_id     number(12),
    contract_name   varchar2(80),
    file_size       number,
    orig_file       blob

)
tablespace users
lob (orig_file)
(

    tablespace users
    enable storage in row
    chunk 4096
    pctversion 20
    nocache
    nologging

);
\

实际的文件以二进制格式存储在 ORIG_FILE 列中。各种参数指明在操作期间不应对 LOB 进行缓存并记入日志中,应按表行存储,块大小应为 4KB 并存储在表空间 USERS 中。由于您没有明确指定,因此 LOB 在 Oracle Database 11g 中以常规格式 (BasicFiles) 存储。

如果您希望将 LOB 存储为 SecureFile,只需在创建表时放入一个子句 store as securefile,如下所示:

create table contracts_sec
(

    contract_id     number(12),
    contract_name   varchar2(80),
    file_size       number,
    orig_file       blob

)
tablespace users
lob (orig_file)

store as securefile
(

    tablespace users
    enable storage in row
    chunk 4096
    pctversion 20
    nocache
    nologging

)
/

要创建 SecureFile LOB,您需要满足两个条件,而这两个条件都是默认设置,因此您可能已经满足。
初始化参数 db_securefile 应设为 permitted(默认设置)。我会在后面解释该参数的作用。
在其中创建 securefile 的表空间应启用自动段空间管理 (ASSM)。在 Oracle Database 11g 中,表空间创建的默认模式为 ASSM,因此该表空间可能已经这样设置。如果没有,则需要在一个新的 ASSM 表空间上创建 SecureFile。
表创建完成后,您可以加载数据,方式与 11g 之前的常规 LOB (BasicFile) 相同。不需要更改应用程序,也不需要记住某些特殊的语法。

下面是一个载入该表的小程序。

declare

l_size      number;  
l_file_ptr  bfile;   
l_blob      blob;    

begin

l_file_ptr := bfilename('SECFILE', 'contract.pdf'); 
dbms_lob.fileopen(l_file_ptr); 
l_size := dbms_lob.getlength(l_file_ptr); 
for ctr in 1 .. 100 loop 
    insert into contracts_sec 
    (        
        contract_id, 
        contract_name, 
        file_size,   
        orig_file    
    )        
    values   
    (        
        ctr,         
        'Contract '||ctr, 
        null,        
        empty_blob() 
    )        
    returning orig_file into l_blob;  
    dbms_lob.loadfromfile(l_blob, l_file_ptr, l_size); 
end loop; 
commit; 
dbms_lob.close(l_file_ptr); 

end;
/

该程序将 contract.pdf 文件分 100 次载入表的 100 个行中。您应该已经为存储 contract.pdf 文件的操作系统目录定义了一个名为 SECFILE 的目录对象。下面的示例指明 contract.pdf 文件在 /opt/oracle 中的位置。

SQL> create directory secfile as ’/opt/oracle’;

将 LOB 存储为 SecureFile 后,您就可以获得很多能优化操作的特性。下面就是其中一些很有用的特性。

重复消除
重复消除可能是 SecureFiles 中最受欢迎的特性,它由于操作系统文件在某些高端文件系统中相对于数据库驻留 BLOB 的优势而备受推崇。假设一个表有五条记录,每条记录有一个 BLOB。其中三个 BLOB 是完全相同的。如果能够只存储该 BLOB 一次而在其他两个记录上只存储对该副本的引用将极大地减少空间消耗。这在操作系统文件中是可行的,但在 Oracle Database 10g LOB 中则无法实现。但是如果使用 SecureFiles,只需通过一个称为重复消除的属性即可轻松搞定。可以在表创建时指定该属性,也可以在以后将其修改为:

SQL> alter table contracts_sec
2 modify lob(orig_file)
3 (deduplicate)
4 /

Table altered.

使用重复消除后,数据库计算每行中各列的散列值并进行相互比较。如果有匹配的散列值,则存储该散列值而不是实际的 BLOB。新记录插入时会计算其散列值,如果其散列值与其他散列值匹配,则插入散列值;否则存储实际的值。

下面,我们来看看进行重复消除过程后的空间节省情况。可以通过程序包 DBMS_SPACE 检查 LOB 段中的空间消耗。下面是一个显示空间消耗的程序:

declare

l_segment_name          varchar2(30); 
l_segment_size_blocks   number; 
l_segment_size_bytes    number; 
l_used_blocks           number;  
l_used_bytes            number;  
l_expired_blocks        number;  
l_expired_bytes         number;  
l_unexpired_blocks      number;  
l_unexpired_bytes       number;  

begin

select segment_name 
into l_segment_name 
from dba_lobs 
where table_name = 'CONTRACTS_SEC'; 
    dbms_output.put_line('Segment Name=' || l_segment_name);

dbms_space.space_usage( 
    segment_owner           => 'ARUP',  
    segment_name            => l_segment_name, 
    segment_type            => 'LOB', 
    partition_name          => NULL, 
    segment_size_blocks     => l_segment_size_blocks, 
    segment_size_bytes      => l_segment_size_bytes, 
    used_blocks             => l_used_blocks, 
    used_bytes              => l_used_bytes, 
    expired_blocks          => l_expired_blocks, 
    expired_bytes           => l_expired_bytes, 
    unexpired_blocks        => l_unexpired_blocks, 
    unexpired_bytes         => l_unexpired_bytes 
);   
dbms_output.put_line('segment_size_blocks       => '||  l_segment_size_blocks);
dbms_output.put_line('segment_size_bytes        => '||  l_segment_size_bytes);
dbms_output.put_line('used_blocks               => '||  l_used_blocks);
dbms_output.put_line('used_bytes                => '||  l_used_bytes);
dbms_output.put_line('expired_blocks            => '||  l_expired_blocks);
dbms_output.put_line('expired_bytes             => '||  l_expired_bytes);
dbms_output.put_line('unexpired_blocks          => '||  l_unexpired_blocks);
dbms_output.put_line('unexpired_bytes           => '||  l_unexpired_bytes);

end;
/

该脚本显示 LOB 各种与空间有关的统计信息。进行重复消除过程之前,输出如下:

Segment Name=SYS_LOB0000070763C00004$$
segment_size_blocks => 1072
segment_size_bytes => 8781824
used_blocks => 601
used_bytes => 4923392
expired_blocks => 448
expired_bytes => 3670016
unexpired_blocks => 0
unexpired_bytes => 0

进行重复消除之后:

Segment Name=SYS_LOB0000070763C00004$$
segment_size_blocks => 1456
segment_size_bytes => 11927552
used_blocks => 7
used_bytes => 57344
expired_blocks => 127
expired_bytes => 1040384
unexpired_blocks => 1296
unexpired_bytes => 10616832

仅以上输出的一个度量标准就足以说明问题:used_bytes。它显示了 LOB 列存储的字节数。使用重复消除之前,需要占用 4,923,392 字节或 5MB,但使用重复消除后,该值缩减为 57,344 字节或大约 57KB,差不多是原来值的 1%。这是因为重复消除过程发现了 100 个具相同值的行(回忆一下,我们将同一个值放到了所有行的 LOB 列中)。重复消除过程只保留了一行而使其他行成为指针。

您也可以反向进行重复消除过程:

SQL> alter table contracts_sec
2 modify lob(orig_file)
3 (keep_duplicates)
4 /

Table altered.

之后,如果您再检查空间:

Segment Name=SYS_LOB0000070763C00004$$
segment_size_blocks => 1456
segment_size_bytes => 11927552
used_blocks => 601
used_bytes => 4923392
expired_blocks => 0
expired_bytes => 0
unexpired_blocks => 829
unexpired_bytes => 6791168

您将发现 USED_BYTES 增加为原来大约 5MB 的值。

压缩
SecureFiles 的另一个特性是压缩。可以使用以下 SQL 压缩 LOB 中存储的值:

SQL> alter table contracts_sec
2 modify lob(orig_file)
3 (compress high)
4 /

Table altered.

现在,如果您运行空间查找 PL/SQL 块:

Segment Name=SYS_LOB0000070763C00004$$
segment_size_blocks => 1456
segment_size_bytes => 11927552
used_blocks => 201
used_bytes => 1646592
expired_blocks => 0
expired_bytes => 0
unexpired_blocks => 1229
unexpired_bytes => 10067968

您将发现 used_bytes 这一度量标准由 5MB 降至现在的 1,646,592,即大约 1.5 MB。

压缩与重复消除不同。压缩在每行的 LOB 列内部发生 — 每个 LOB 列单独压缩。在重复消除过程中,所有行都受到检查,列中的重复值将进行删除并替换为指针。如果您有两个完全不同的行,重复消除不会减少占用空间;但是压缩可以优化 LOB 值的空间。除了对表执行重复消除过程,您还可以对表进行压缩。

由于压缩占用 CPU 周期,因此如果数据压缩量不大,可能并不值得进行压缩。例如,如果您有大量已经压缩过的 JPEG 照片,那么进一步的压缩不会节省任何空间。但是,如果您有一个作为 CLOB 存储的 XML 文档,那么压缩可以节省大量空间。SecureFiles 压缩自动检测数据是否可压缩并仅在压缩可以节省空间时占用 CPU 周期。

Oracle Text 索引可以在压缩过的 SecureFiles LOB 上安装。较之文件系统中的压缩文件,这是在 Oracle 数据库中存储非结构化数据的主要好处。

此外,请注意,LOB 压缩与表压缩无关。压缩表 CONTRACTS_SEC 并不会压缩 LOB。LOB 压缩仅在您执行上述 SQL 时才会发生。

在 Oracle Database 11g 第 2 版中,除了 HIGH 和 MEDIUM 两个选项外,还提供了第三个压缩选项:LOW。顾名思义,该选项的压缩率比较低,但占用的 CPU 也要少得多,能够更快速地完成压缩。这种方法使用类似于快速 Lempel–Ziv–Oberhumer (LZO) 算法的基于块的无损压缩。

我们来看一个使用 SecureFiles LOW 压缩的表的示例:

create table docs
(

    doc_id  number,
    clearance       varchar2(20),
    doc_body        clob

)
LOB(doc_body) store as securefile
(

    compress low

)
/

如果您省略了 LOW 子句,则默认选项为 MEDIUM。LOW 压缩不仅适用于表创建,还可用于更改已有的列。

我们来看一个使用相同表和列的示例。首先,我们将该列修改为未压缩:

SQL> alter table docs
2 modify LOB(doc_body)
3 (
4 nocompress
5 )
6 /

Table altered.

现在,我们将该列修改为使用 LOW 压缩:

SQL> alter table docs
2 modify LOB(doc_body)
3 (
4 compress low
5 )
6 /

Table altered.

加密
您可以对 SecureFiles 使用透明数据库加密,就像您将对任何列所做的一样。下面说明如何使用 AES 128 位加密对列 orig_file LOB 进行加密。

alter table contracts_sec
modify lob(orig_file)
(encrypt using 'AES128')
/

启用加密之前,您需要设置加密钱夹。(加密钱夹的完整描述可以在此 Oracle Magazine 文章中找到。)下面是总结的几个步骤:

在 sqlnet.ora 中设置参数(如果尚未设置)以指定钱夹的位置:
ENCRYPTION_WALLET_LOCATION=
(SOURCE=

   (METHOD=FILE) 
   (METHOD_DATA= 
      (DIRECTORY= /opt/oracle/orawall)
 )        

)
目录 /opt/oracle/orawall 应该已经存在;如果不存在,则应创建该目录。
创建钱夹:
alter system set encryption key authenticated by "mypass"
这将创建口令为 mypass 的钱夹并将其打开。
上述步骤只需执行一次。钱夹创建并打开后,只要数据库在运行它就会一直打开(除非人为关闭)。如果数据库重启,您需要通过以下语句打开钱夹:
alter system set encryption wallet open identified by "mypass"
当 SecureFile LOB 列得到加密后,该表所有行的列值都会得到加密。加密后,您不能在表中使用常规导出或导入;您需要使用 Data Pump。
您可以查看视图 dba_encrypted_columns 了解哪些列已得到加密以及加密的方式。

SQL> select table_name, column_name, encryption_alg
2 from dba_encrypted_columns
3 /

TABLE_NAME COLUMN_NAME ENCRYPTION_ALG
------------------------------ ------------------ -----------------------------
CONTRACTS_SEC ORIG_FILE AES 128 bits key

缓存
较之数据库驻留对象,在操作系统文件中存储非结构化数据的优势之一是缓存工具。文件可以在操作系统的文件缓冲区中进行缓存。数据库驻留对象还可以在数据库缓冲区缓存中进行缓存。但是,在某些情况下,缓存可能会损害性能。LOB 通常都很大(该术语大对象就是因此得名),如果它们进入缓冲区缓存,大多数其他的数据块将需要被推送出缓存以便为要进来的 LOB 腾出空间。该 LOB 可能以后永远都不会使用,但是它进入缓冲区缓冲却会导致某些必需的数据块被赶出去。因此,在大多数情况下,您可能希望对 LOB 禁用缓存。

在针对 CONTRACTS_SEC 的示例脚本中,您使用了 nocache 子句来禁用缓存。要为 LOB 启用缓存,您可以对该表进行以下更改:

alter table contracts_sec
modify lob(orig_file)
(cache)
/

这将启用 LOB 缓存。注意该缓存只引用 LOB。表的其余部分放入缓冲区缓存,并遵循任何其他表的逻辑(无论该表上的 LOB 缓存如何设置)。

缓存的优点是非常依赖于应用程序。在处理缩略图的应用程序中,使用缓存可能会提高性能。但是,对于大型文档或图像,最好关闭缓存。您可以通过 securefiles 进行控制。

日志记录
日志记录子句决定 LOB 中的数据更改如何记录到重做日志流中。与任何其他数据一样,默认设置为完全日志记录,但是由于 LOB 中的数据通常都很大,在某些情况下,您可能希望不进行日志记录。上述示例中的 NOLOGING 子句就可以实现该目的。

SecureFiles 为该子句提供了另一个值 filesystem_like_logging,如下所示:

create table contracts_sec_fs
(

    contract_id     number(12),
    contract_name   varchar2(80),
    file_size       number,
    orig_file       blob

)
tablespace users
lob (orig_file)
store as securefile
(

    tablespace users
    enable storage in row
    chunk 4096
    pctversion 20
    nocache
    
                          

filesystem_like_logging
)

注意以黑体显示的行,它将 LOB 元数据记录到重做日志中,而不是记录整个 LOB。这类似于文件系统。文件元数据记录到文件系统日志中。同样,SecureFiles 上的该子句会加速崩溃后的恢复。

管理
数据字典视图 DBA_LOBS 显示了数据库中 LOB 的属性(包括 SecureFiles)。下面是该视图的列:

列名 描述
OWNER

表的所有者

TABLE_NAME

表的名称

COLUMN_NAME

LOB 列的名称

SEGMENT_NAME

LOB 作为单独的段存储,由用户命名,默认为 SYS_LOB…

TABLESPACE_NAME

表空间的名称

INDEX_NAME

LOB 索引的名称

CHUNK

LOB 的块大小

PCTVERSION

在 SecureFiles 中忽略

RETENTION

如果 SecureFile LOB 进行了更新,以前的图像与任何其他数据库块一样保存在还原段中;但是与数据库块不同的是,您可以指定以前的图像保存多长时间(保留期)。

FREEPOOLS

对 SecureFiles 忽略

CACHE

SecureFile LOB 是否在缓冲池中缓冲 (Yes/No),本文已说明

LOGGING

是否记录对 SecureFile LOB 进行的更改 (Yes/No),本文已说明

ENCRYPT

SecureFile LOB 是否已加密 (Yes/No),本文已说明

COMPRESSION

SecureFile LOB 是否已压缩 (Yes/No),本文已说明

DEDUPLICATION

Securefile LOB 是否已进行重复消除 (Yes/No),本文已说明

IN_ROW

LOB 是否按表行存储

FORMAT

LOB 是否与平台的字节顺序有关

PARTITIONED

LOB 是否在分区表上

SECUREFILE

LOB 是 SECUREFILE (Yes/No) 还是 BASICFILE

在分区表上,LOB 信息存储在视图 DBA_LOB_PARTITIONS 中。

LOB 到 SecureFiles 的迁移
既然已经了解 SecureFiles 是多么有用,您可能希望对现有的表进行转换。最简单的方法是创建一个新表,载入旧表中的数据,然后重命名该表。(当然,这要求这些表在操作期间不可用。)另一种方法是使用 dbms_redefinition 程序包联机重新定义表,不影响可用性。

我们通过一个示例来了解该过程。假设您希望迁移原始表 CONTRACTS_BASIC 以存储为 SecureFiles。要实现该目的,执行以下步骤。

确保您具有一个主键。如果没有,创建一个。

alter table contracts_basic
add constraint pk_contacts
primary key (contract_id)
/

构建新表。

create table contracts_new
(
contract_id number(12),
contract_name varchar2(80),
file_size number,
orig_file BLOB
)
lob (orig_file)
store as securefile
(nocache nologging)
/

将列映射到新表。

declare
l_col_mapping varchar2(1000);
begin
l_col_mapping :=

 'contract_id contract_id , '||
 'contract_name contract_name , '||
 'file_size file_size, '||
 'orig_file orig_file';
 dbms_redefinition.start_redef_table
   ('ARUP', 'CONTRACTS_BASIC', 'CONTRACTS_NEW', l_col_mapping);

end;
/

开始重新定义过程。

declare
l_error_count pls_integer := 0;
begin
dbms_redefinition.copy_table_dependents
(

  'ARUP', 'CONTRACTS_BASIC', 'CONTRACTS_NEW',
  1, TRUE, TRUE, TRUE, FALSE, l_error_count

);
dbms_output.put_line('Errors Occurred := ' ||

   to_char(l_error_count));

end;
/

这会将 CONTRACTS_BASIC 中的所有行复制到 CONTRACTS_NEW 中,因此,根据表的行数,该操作可能需要较长时间。
完成重新定义过程。

begin

dbms_redefinition.finish_redef_table
   ('ARUP', 'CONTRACTS_BASIC', 'CONTRACTS_NEW');

end;
/

确认表已进行转换。

select securefile
from dba_lobs
where table_name = 'CONTRACTS_BASIC'
/

SEC

YES

列显示 YES,表明列已转换为 SecureFiles。

删除临时表 CONTRACTS_NEW。

SQL> drop table contracts_new;

Table dropped.

您可以尝试在开始就启用并行 DML 以加快复制过程。下面说明如何在会话中启用并行 DML:

alter session force parallel dml;

初始化参数
初始化参数 db_securefile 决定 SecureFiles 在数据库中的使用。下面是该参数的各种值及其效果:

效果

PERMITTED

默认值。该值指明可以在数据库中创建 SecureFile LOB。

ALWAYS

既然您已经知道了 SecureFiles 是多么有用,您可能希望确保所有 LOB 创建后就应该仅为 SecureFiles 而非默认的 BasicFiles(即使用户没有指定 securefile)。该参数值确保所有 LOB 默认情况下创建为 SecureFiles。记住,SecureFiles 需要 ASSM 表空间(在 11g 中为默认设置),因此如果您尝试在非 ASSM 表空间中创建 LOB,将出现错误。

NEVER

与 always 值相反。由于某种原因,您不喜欢 SecureFiles 并且不希望允许它在数据库中创建。即使使用 SecureFile 子句,该参数值仍然会将 LOB 创建为 BasicFile。当使用了 SecureFile 子句而 LOB 仍然创建为默认的 BasicFile 时,用户不会收到错误消息。

IGNORE

忽略 securefile 子句以及所有存储子句。

总结
SecureFiles 不仅是新一代 LOB,它们还为 LOB 带来了更多的价值,尤其是以前只能在文件系统领域中获得的特性。SecureFiles 可以进行加密以确保安全性,可以进行重复消除和压缩以提高存储效率,可以进行缓存(或不进行缓存)以加快访问(或节省缓冲池空间),可以按多个级别记录以减少崩溃后的平均恢复时间。引入 SecureFiles 后,您可以在数据库中存储更多的非结构化文档,而不会导致过多的开销,也不会失去 OS 文件系统提供的任何重要功能。

上一篇:silverlight-带水印的自定义TextBox控件(版本2)


下一篇:使用 BFO 方式安装 Fedora 20