LOB型別

jelephant發表於2013-12-21
1、clob/blob
建立一個lob列時,儲存在行中的只是一個指標,當我們請求得到lob資料時,lob指標將透過lobindex找到資料的儲存位置,然後訪問lobsegment獲取資料。

表空間
lob欄位與表放在不同的表空間,主要與管理和效能有關。一方面,為lob資料單獨使用一個表空間有利於備份和恢復以及空間管理。另一方面,預設情況下lob不在快取區中進行快取,對於每個lob訪問,不論是讀還是寫,都會帶來一個IO,所以將這些物件分離到他們自己的磁碟上就很有意義。另外需要說明,logindex和logsegment總會在同一個表空間中。

in row 子句
這控制了lob資料是否總與表分開儲存。如果設定了enable storage in row(預設設定) ,小lob(最多4000位元組)就會像varchar2一樣儲存在表本身中,只有當lob超過了4000位元組時,才會移出到lobsegment中。如果lob欄位資料小於4000位元組,建議採用行記憶體儲,即預設設定。

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

Table created.

JEL@JEL >insert into t
  2  select rownum,
  3  owner||' '||object_name||' '||object_type||' '||status,
  4  owner||' '||object_name||' '||object_type||' '||status
  5  from all_objects;

9345 rows created.

JEL@JEL >alter session set SQL_TRACE=TRUE;

Session altered.

JEL@JEL >declare                       
  2  l_cnt number;
  3  l_data varchar2(4000);
  4  begin
  5  select count(*) into l_cnt from t;
  6  for i in 1 .. l_cnt
  7  loop
  8  select in_row into l_data from t where id=i;
  9  select out_row into l_data from t where id=i;
 10  end loop;
 11  end;
 12  /

PL/SQL procedure successfully completed.

[oracle@jelephant ~]$ tkprof /u01/app/oracle/admin/JEL/udump/jel_ora_4540.trc /u01/app/oracle/admin/JEL/udump/jel_ora_4540.txt

跟蹤檔案如下:
********************************************************************************

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   9345      0.03       0.16          0          0          0           0
Fetch     9345      0.08       0.19          0      28035          0        9345
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total    18691      0.11       0.36          0      28035          0        9345

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

Rows     Row Source Operation
-------  ---------------------------------------------------
   9345  TABLE ACCESS BY INDEX ROWID T (cr=28035 pr=0 pw=0 time=199495 us)
   9345   INDEX UNIQUE SCAN SYS_C002903 (cr=18690 pr=0 pw=0 time=96206 us)(object id 10067)

********************************************************************************

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   9345      0.07       0.16          0          0          0           0
Fetch     9345      1.08       0.57       9345      56072          0        9345
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total    18691      1.15       0.73       9345      56072          0        9345

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

Rows     Row Source Operation
-------  ---------------------------------------------------
   9345  TABLE ACCESS BY INDEX ROWID T (cr=28035 pr=0 pw=0 time=208311 us)
   9345   INDEX UNIQUE SCAN SYS_C002903 (cr=18690 pr=0 pw=0 time=102863 us)(object id 10067)
********************************************************************************

獲取in_row列顯然快的多,而且所佔的資源也遠遠少於獲取out_row列。這種行內行外儲存設定不僅會影響讀,還會影響修改。


chunk子句
lob儲存在塊(chunk)中,指向lob資料的索引會指向各個資料塊。塊(chunk)是邏輯上連續的一直資料庫塊(block),這也是lob的最小分配單元,但通常資料塊的最小分配單元是資料塊庫塊。chunk大小必須是block的整數倍。
注意兩點,第一,一個chunk只能由一個lob值使用,每個lob值會佔用至少一個chunk。如果一個表有100行,每行有一個包含7kb資料的lob。oracle就分配100個chunk,如果將chunk大小設定成32kb,就會分配100*32kb的空間,從而產生大量空間浪費。第二,讓每個lob值相應的chunk數減至最少,lobindex用於指向各個塊,塊越多,索引就越大。

pctversion子句
用於控制lob的讀一致性。lobsegment並不使用undo來記錄其修改,而是直接在lobsegment本身中維護資訊的版本,而lobindex會像其他段一樣上傳undo。修改一個lob時,oracle會分配一個新chunk,並且仍保留原來的chunk。如果回滾事務,對lobindex所做的修改會回滾,索引將再次指向原來的chunk。

如果不用undo段來儲存回滾lob所需的資訊,而且lob支援讀一致性,那麼怎麼避免ORA-1555:snapshot too old錯誤呢?這正是pctversion起作用的地方
如果處理lob是遇到了ORA-22924錯誤,解決方案是執行如下命令:
alter table tabname modify lob (lobname)(pctversion n)


cache子句
預設nocache
cache reads 允許快取從磁碟讀取得lob資料,但是lob資料的寫操作則直接寫至磁碟。cache則允許讀和寫都能快取lob資料,建議對小lob進行快取。
 alter table tabname modify lob (lobname)(cache)
alter table tabname modify lob (lobname)(nocache)

2、bfile
它只是作業系統上一個檔案的指標,它用於為這些作業系統檔案提供只讀訪問。
JEL@JEL >create table t_file (id int primary key,os_file bfile);

Table created.

JEL@JEL >create or replace directory my_dir as '/home/oracle/';

Directory created.

JEL@JEL >insert into t_file values (1,bfilename('MY_DIR','db.txt'));

1 row created.

JEL@JEL >commit;

Commit complete.

JEL@JEL >select dbms_lob.getlength(os_file) from t_file;

DBMS_LOB.GETLENGTH(OS_FILE)
---------------------------
                        951

檔案大小為951kb,注意儲存是要求MY_DIR必須為大寫。

讀取檔案:
JEL@JEL >grant read,write on directory my_dir to public;

Grant succeeded.

JEL@JEL > SET SERVEROUTPUT ON

指令碼如下:
declare
    fhandle utl_file.file_type;
    f_buffer varchar2(4000);
begin
    fhandle := utl_file.fopen('MY_DIR','db.txt','r');
    loop
      begin
      utl_file.get_line(fhandle,f_buffer);
      dbms_output.put_line(f_buffer);
      exception
      when no_data_found then
        exit;
      end;
    end loop;
    utl_file.fclose(fhandle);
end;

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/29337971/viewspace-1063972/,如需轉載,請註明出處,否則將追究法律責任。

相關文章