Oracle外部表詳解 轉
外部表概述
外部表只能在Oracle 9i之後來使用。簡單地說,外部表,是指不存在於資料庫中的表。通過向Oracle提供描述外部表的元資料,我們可以把一個作業系統檔案當成一個只讀的資料庫表,就像這些資料儲存在一個普通資料庫表中一樣來進行訪問。外部表是對資料庫表的延伸。
外部表的特性
位於檔案系統之中,按一定格式分割,如文字檔案或者其他型別的表可以作為外部表。
對外部表的訪問可以通過SQL語句來完成,而不需要先將外部表中的資料裝載進資料庫中。
外部資料表都是隻讀的,因此在外部表不能夠執行DML操作,也不能建立索引。
ANALYZE語句不支援採集外部表的統計資料,應該使用DMBS_STATS包來採集外部表的統計資料。
建立外部表的注意事項
1.需要先建立目錄物件
在建立物件的時候,需要小心,Oracle資料庫系統不會去確認這個目錄是否真的存在。如果在輸入這個目錄物件的時候,不小心把路徑寫錯了,那可能這個外 部表仍然可以正常建立,但是卻無法查詢到資料。由於建立目錄物件時,缺乏這種自我檢查的機制,為此在將路徑賦予給這個目錄物件時,需要特別的注意。另外需 要注意的是路徑的大小寫。在Windows作業系統中,其路徑是不區分大小寫的。而在Linux作業系統,這個路徑需要區分大小寫。故在不同的作業系統 中,建立目錄物件時需要注意這個大小寫的差異
2.對於作業系統檔案的要求
建立外部表時,必須指定作業系統檔案所使用的分隔符號。並且該分隔符有且只有一個。建立外部表時,不能含有標題列。如果這個標題資訊與外部表的欄位型別不一致(如欄位內容是number資料型別,而標題資訊則是字元型資料,則在查詢時就會出錯)。如果資料型別恰巧一致的話,這個標題資訊Oracle資料庫也會當作普通記錄來對待。
當Oracle資料庫系統訪問這個作業系統檔案的時候,會在這個檔案所在的目錄自動建立一個日誌檔案。無論最後是否訪問成功,這個日誌檔案都會如期建立。檢視這個日誌檔案,可以瞭解資料庫訪問外部表的頻率、是否成功訪問等等。預設情況下,該日誌在與外部表的相同directory下產生。
3.在建立臨時表時的相關限制
對錶中欄位的名稱存在特殊字元的情況下,必須使用英文狀態的下的雙引號將該表列名稱連線起來。如採用”SalseID#”。
對於列名字中特殊符號未採用雙引號括起來時,會導致無法正常查詢資料。
建議不用使用特殊的列標題字元
在建立外部表的時候,並沒有在資料庫中建立表,也不會為外部表分配任何的儲存空間。
建立外部表只是在資料字典中建立了外部表的元資料,以便對應訪問外部表中的資料,而不在資料庫中儲存外部表的資料。
簡單地說,資料庫儲存的只是與外部檔案的一種對應關係,如欄位與欄位的對應關係。而沒有儲存實際的資料。
由於儲存實際資料,故無法為外部表建立索引,同時在資料使用DML時也不支援對外部表的插入、更新、刪除等操作。
4.刪除外部表或者目錄物件
一般情況下,先刪除外部表,然後再刪除目錄物件,如果目錄物件中有多個表,應刪除所有表之後再刪除目錄物件。
如果在未刪除外部表的情況下,強制刪除了目錄,在查詢到被刪除的外部表時,將收到"物件不存在"的錯誤資訊。
查詢dba_external_locations來獲得當前所有的目錄物件以及相關的外部表,同時會給出這些外部表所對應的作業系統檔案的名字。如果只是在資料庫層面上刪除外部表,並不會自動刪除作業系統上的外部表文件。
5.對於作業系統平臺的限制
不同的作業系統對於外部表有不同的解釋和顯示方式
如在Linux作業系統中建立的檔案是分號分隔且每行一條記錄,但該檔案在Windows作業系統上開啟則並非如此。
建議避免不同作業系統以及不同字符集所帶來的影響
建立外部表
使用CREATE TABLE語句的ORGANIZATION EXTENERAL子句來建立外部表。外部表不分配任何盤區,因為僅僅是在資料字典中建立元資料。
1.外部表的建立語法
createtabletable_name
(col1 datatype1,col2 datatype2,col3 datatype3)
organization exteneral
(.....)
詳細語法可參見筆者的另兩篇文章
Oracle外部表ORACLE_DATAPUMP型別的建立語法詳解:http://czmmiao.iteye.com/blog/1268453
Oracle外部表ORACLE_LOADER型別的建立語法詳解:http://czmmiao.iteye.com/blog/1268157
2.由查詢結果集,使用Oracle_datapump來填充資料來生成外部表
a.建立系統目錄以及Oracle資料目錄名來建立對應關係,同時授予許可權
$ mkdir -p /home/oracle/external_tb/data
create or replace directory data_dir as '/home/oracle/external_tb/data/'; grant read,write on directory data_dir to scott;
b.建立外部表
create table ex_tb1 (ename,job,sal,dname) organization external (type oracle_datapump default directory data_dir location('ex_tb1')) parallel 1 as select ename,job,sal,dname from emp join dept on emp.deptno=dept.deptno;
c.驗證外部表
select * from ex_tb1; ENAME JOB SAL DNAME ------------------------- -------------------- ---- ------------------------- CLARK MANAGER 2450 ACCOUNTING KING PRESIDENT 5000 ACCOUNTING MILLER CLERK 1300 ACCOUNTING JONES MANAGER 2975 RESEARCH FORD ANALYST 3000 RESEARCH ADAMS CLERK 1100 RESEARCH SMITH CLERK 800 RESEARCH SCOTT ANALYST 3000 RESEARCH WARD SALESMAN 1250 SALES TURNER SALESMAN 1500 SALES ALLEN SALESMAN 1600 SALES JAMES CLERK 950 SALES BLAKE MANAGER 2850 SALES MARTIN SALESMAN 1250 SALES 14 rows selected.
對於使用上述方式建立的外部表可以將其複製到其他路徑作為外部表的原始資料來生成新的外部表,用於轉移資料。
d.將外部表文件複製一個新的檔名,用以模擬到其他伺服器上
$ cp /home/oracle/external_tb/data/ex_tb1 /home/oracle/external_tb/data/in_tb1
e. 新建表,將上述外部表的資料匯入到新表中
create table in_tb1 (ename varchar2(10),job varchar2(9),sal number(7,2),dname varchar(14)) organization external (type oracle_datapump default directory data_dir location('in_tb1'));
f.驗證新外部表的資料
select * from in_tb1; ENAME JOB SAL DNAME ------------------------- -------------------- ---- ------------------------- CLARK MANAGER 2450 ACCOUNTING KING PRESIDENT 5000 ACCOUNTING MILLER CLERK 1300 ACCOUNTING JONES MANAGER 2975 RESEARCH FORD ANALYST 3000 RESEARCH ADAMS CLERK 1100 RESEARCH SMITH CLERK 800 RESEARCH SCOTT ANALYST 3000 RESEARCH WARD SALESMAN 1250 SALES TURNER SALESMAN 1500 SALES ALLEN SALESMAN 1600 SALES JAMES CLERK 950 SALES BLAKE MANAGER 2850 SALES MARTIN SALESMAN 1250 SALES 14 rows selected.
g.建立正常的表,將外部表資料匯入,這就是利用ORACLE_DATAPUMP型別的額外部表實現資料遷移
create table tb1 as select * from in_tb1;
3.使用外部檔案資料,使用oracle_loader來填充資料來生成外部表
a.準備外部資料來源檔案
cat /home/oracle/external_tb/data/1.txt "7369","SMITH","CLERK","7902","17-DEC-80","100","0","20" "7499","ALLEN","SALESMAN","7698","20-FEB-81","250","0","30" "7521","WARD","SALESMAN","7698","22-FEB-81","450","0","30" "7566","JONES","MANAGER","7839","02-APR-81","1150","0","20" $ cat /home/oracle/external_tb/data/2.txt "7654","MARTIN","SALESMAN","7698","28-SEP-81","1250","0","30" "7698","BLAKE","MANAGER","7839","01-MAY-81","1550","0","30" "7934","MILLER","CLERK","7782","23-JAN-82","3500","0","10"
b.建立外部表
create table emp_new( emp_id number(4), ename varchar2(15), job varchar2(12), mgr_id number(4), hiredate date, salary number(8), comm number(8), dept_id number(2) ) organization external ( type oracle_loader default directory data_dir access parameters( records delimited by newline badfile 'emp_new%a_%p.bad' logfile 'emp_new%a_%p.log' fields terminated by ',' optionally enclosed by '"' lrtrim missing field values are null reject rows with all null fields ) location ('1.txt','2.txt') ) parallel reject limit unlimited;
c.驗證外部表
select * from emp_new; EMP_ID ENAME JOB MGR_ID HIREDATE SALARY COMM DEPT_ID ------ ---------- --------------- ---------- ------------------- ---------- ---------- ---------- 7654 MARTIN SALESMAN 7698 1981-09-28 00:00:00 1250 0 30 7698 BLAKE MANAGER 7839 1981-05-01 00:00:00 1550 0 30 7934 MILLER CLERK 7782 1982-01-23 00:00:00 3500 0 10 7369 SMITH CLERK 7902 1980-12-17 00:00:00 100 0 20 7499 ALLEN SALESMAN 7698 1981-02-20 00:00:00 250 0 30 7521 WARD SALESMAN 7698 1981-02-22 00:00:00 450 0 30 7566 JONES MANAGER 7839 1981-04-02 00:00:00 1150 0 20 7 rows selected.
4.外部表相關檢視
a.檢視外部表資訊
select TABLE_NAME,TYPE_NAME,DEFAULT_DIRECTORY_NAME,REJECT_LIMIT,ACCESS_PARAMETERS from user_external_tables;
b.獲得平面檔案的位置
select * from user_external_locations order by table_name; TABLE_NAME LOCATION DIRECTORY DIRECTORY_NAME ---------- ---------- --------- -------------------- EMP_NEW 1.txt SYS DATA_DIR EMP_NEW 2.txt SYS DATA_DIR EX_TB1 ex_tb1 SYS DATA_DIR IN_TB1 in_tb1 SYS DATA_DIR
外部表定義的幾個重點
1.ORGANIZATION EXTERNAL關鍵字,必須要有。以表明定義的表為外部表。
2..重要引數外部表的型別
ORACLE_LOADER:定義外部表的預設方式,只能只讀方式實現文字資料的裝載。
ORACLE_DATAPUMP:支援對資料的裝載與解除安裝,資料檔案必須為二進位制dump檔案。可以從外部表提取資料裝載到內部表,也可以從內部表解除安裝資料作為二進位制檔案填充到外部表。
3.DEFAULT DIRECTORY:預設的目錄指明瞭外部檔案所在的路徑
4.LOCATION:定義了外部表的位置
5.ACCESS PARAMETERS:描述如何對外部表進行訪問
RECORDS關鍵字後定義如何識別資料行
DELIMITED BY 'XXX'——換行符,常用newline定義換行,並指明字符集。對於特殊的字元則需要單獨定義,如特殊符號,可以使用OX'十六位值',例如tab(/t)的十六位是9,則DELIMITEDBY0X'09';
cr(/r)的十六位是d,那麼就是DELIMITEDBY0X'0D'。
SKIP X ——跳過X行資料,有些檔案中第一行是列名,需要跳過第一行,則使用SKIP 1。
FIELDS關鍵字後定義如何識別字段,常用的如下:
FIELDS:TERMINATED BY 'x'——欄位分割符。
ENCLOSED BY 'x'——欄位引用符,包含在此符號內的資料都當成一個欄位。
例如一行資料格式如:"abc","a""b,""c,"。使用引數TERMINATED BY ',' ENCLOSED BY '"'後,系統會讀到兩個欄位,第一個欄位的值是abc,第二個欄位值是a"b,"c,。
LRTRIM ——刪除首尾空白字元。
MISSING FIELD VALUES ARE NULL——某些欄位空缺值都設為NULL。
對於欄位長度和分割符不確定且準備用作外部表文件,可以使用UltraEdit、Editplus等來進行分析測試,如果檔案較大,則需要考慮將檔案分割成小檔案並從中提取資料進行測試。
外部表對錯誤的處理
REJECT LIMIT UNLIMITED
在建立外部表時最後加入LIMIT子句,表示可以允許錯誤的發生個數。預設值為零。設定為UNLIMITED則錯誤不受限制
BADFILE和NOBADFILE子句
用於指定將捕獲到的轉換錯誤存放到哪個檔案。如果指定了NOBADFILE則表示忽略轉換期間的錯誤
如果未指定該引數,則系統自動在源目錄下生成與外部表同名的.BAD檔案BADFILE記錄本次操作的結果,下次將會被覆蓋 LOGFILE和NOLOGFILE子句
同樣在access parameters中加入LOGFILE 'LOG_FILE.log'子句,則所有Oracle的錯誤資訊放入'LOG_FILE.log'中
而NOLOGFILE子句則表示不記錄錯誤資訊到log中,如忽略該子句,系統自動在源目錄下生成與外部表同名的.LOG檔案
注意以下幾個常見的問題
1.外部表經常遇到BUFFER不足的情況,因此儘可能的增大READSIZE
2.換行符不對產生的問題。在不同的作業系統中換行符的表示方法不一樣,碰到錯誤日誌提示如是換行符問題,可以使用
UltraEdit開啟,直接看十六進位制
3.特定行報錯時,檢視帶有"BAD"的日誌檔案,其中儲存了出錯的資料,用記事本開啟看看那裡出錯,是否存在於外部表定義相沖突
外部表的侷限性
1.SQLLDR可以指定多少提交一次,即ROWS=?, 外部表卻沒有,這對於大資料量的匯入有些不方例。
2.sqlldr errors表示允許錯誤的行數,外部表用REJECT LIMIT UNLIMITED,這個功能上基本相同。
3.外部表的列不能指定為not nullable,這樣就很難拒絕某列為空值的記錄。
4.外部表不能使用continueif ,如果記錄有換行的就比較難處理。