1. LOB 指针
首先你应该了解的概念是 LOB 指针,它指向 Oracle 中存储大对象的数据的位置。我们举个小例子来说明一下:
我发出这样的查询:
DECLARE
photo BLOB; BEGIN SELECT falls_photo INTO photo FROM waterfalls WHERE falls_name='Dryer Hose';
...
|
大字段 falls_photo 中的数据真的被赋值给变量 photo 了吗?没有,变量 photo 中存储的只是指向 falls_photo 中数据的指针。就像下面的图中所示:
这跟我们以前所使用的其他数据类型不同,数据库中的 LOB 列中存储的不是实际的数据,而是指向 LOB 数据存储位置的指针。同样,PL/SQL 的 LOB 变量中存储的也是指针,它指向该 LOB 数据实际的存储位置。要想处理 LOB 数据,你首先得获取到这个 LOB 指针,然后使用系统包 DBMS_LOB 来处理实际的 LOB 数据。例如,处理存储在列 waterfalls.photo 中的 BLOB 数据的步骤如下:
(1)使用 SELECT 获取到指向 BLOB 数据的指针(就像上面的 SQL);
(2)调用系统过程 DBMS_LOB.OPEN 打开这个 BLOB 指针;
(3)调用系统过程 DBMS_LOB.GETCHUNKSIZE,得到 读/写 该 BLOB 数据的最佳块尺寸;
(4)调用系统过程 DBMS_LOB.GETLENGTH,得到该 BLOB 数据的字节或字符长度;
(5)多次调用系统过程 DBMS_LOB.READ,分批得到该 BLOB 数据;
(6)关闭该 BLOB。
看不懂?没关系,后面我们会详细介绍。
很繁琐?是的,这看起来很笨拙,不过从实用角度看,这是一种很巧妙的处理方法。因为从表中获取一行数据的时候,不会一下子将 LOB 字段的数据全部检索出来。设想一下,若是你获取一个 128T 大小的 LOB 字段,将会花费多长时间?而且,若你只是想得到结果集中的很小一部分,那就更浪费时间了。而用 Oracle 现在所提供的方法,你先很迅速地获取到该 LOB 的指针,再根据该指针获取你所需要的 LOB 数据。是不是很巧妙?
Oracle's LOB DocumentationIf you are working with LOBs, we strongly recommend that you familiarize yourself with the following portions of Oracle's documentation set:
This is not an exhaustive list of LOB documentation, but you'll find all the essential information in these sources. |
2. Empty LOBS 与 NULL LOBs
现在你明白了 LOB 指针与 LOB 数据的关系了吧?那么我们来讲另外一个重要的概念:empty LOB。empty LOB 是指该 LOB 字段或变量中保存了一个 LOB 指针,但这个指针并没有指向任何 LOB 数据。它跟 NULL 不同,NULL 表示该 LOB 字段或变量中连 LOB 指针都没有。有点乱?那我们举个例子:
SQL> set serveroutput on
SQL> DECLARE 2 directions CLOB; 3 BEGIN 4 IF directions IS NULL THEN 5 DBMS_OUTPUT.PUT_LINE('directions is NULL'); 6 ELSE 7 DBMS_OUTPUT.PUT_LINE('directions is not NULL'); 8 END IF; 9 END; 10 / directions is NULL
PL/SQL 过程已成功完成。
|
这个例子是关于 NULL LOBs 的。跟我们以前使用过的类型没有什么区别:定义了一个变量,但并没有给它赋值,那么它就是 NULL。我们再看 empty LOBs 是怎么回事:
SQL> DECLARE
2 directions CLOB; 3 BEGIN 4 --Insert a new row using EMPTY_CLOB( ) to create a LOB locator 5 INSERT INTO waterfalls 6 (falls_name,falls_directions) 7 VALUES ('Munising Falls',EMPTY_CLOB( )); 8 9 --Retrieve the LOB locater created by the previous INSERT statement 10 SELECT falls_directions 11 INTO directions 12 FROM waterfalls 13 WHERE falls_name='Munising Falls'; 14 15 IF directions IS NULL THEN 16 DBMS_OUTPUT.PUT_LINE('directions is NULL'); 17 ELSE 18 DBMS_OUTPUT.PUT_LINE('directions is not NULL'); 19 END IF; 20 21 DBMS_OUTPUT.PUT_LINE('Length = ' || DBMS_LOB.GETLENGTH(directions)); 22 END; 23 / directions is not NULL Length = 0
PL/SQL 过程已成功完成。
|
这里使用到了系统函数 EMPTY_CLOB(),它返回一个 CLOB 指针。二进制大字段变量 directions 不是 NULL,因为它存储了一个 CLOB 指针,但它的长度是 0,说明这个指针并没有指向任何数据。这里的变量 directions 就是一个 empty LOB。
理解 null LOBs 和 empty LOBs 的区别很重要,因为很多时候,你要测试 LOB 中是否存在数据,它将比其他类型稍微复杂点。
测试普通的类型,只需要这样就可以了:
IF some_number IS NULL THEN
--You know there is no data |
而对于 LOB 类型,你不但要测试 NULL,还要测试 empty,而且顺序不能颠倒:
IF some_clob IS NULL THEN
--There is no data ELSEIF DBMS_LOB.GETLENGTH(some_clob) = 0 THEN --There is no data ELSE --Only now is there data END IF; |