Oracle 外部表(External Tables)使用总结
一、外部表概述
外部表(External Table) 是 Oracle 数据库中的一种特殊表对象,它不存储数据在数据库中,而是允许数据库以只读方式访问操作系统上的文件(如 CSV、定长文本、数据泵导出文件等),将其视为数据库表进行查询,甚至可与普通表进行 JOIN、INSERT 等操作。
核心特点:
- 数据存储在外部:数据保存在数据库外部的文件中,不占用数据库表空间。
- 只读访问 :通常只能查询,不能对外部表执行 DML(但可通过
INSERT ... SELECT将数据导入普通表)。 - 两种驱动类型 :
ORACLE_LOADER:用于读取文本文件(CSV、定宽等),通过访问参数解析。ORACLE_DATAPUMP:用于读取数据泵(expdp)生成的二进制文件,支持数据的卸载和重新加载。
关键视图:
sql
dba_external_tables; -- 显示所有外部表的信息
二、环境准备
1. 创建目录对象
sql
create directory ext_dir as '/home/oracle/dh';
grant all on directory ext_dir to user1;
作用:
CREATE DIRECTORY:创建名为ext_dir的目录对象,映射到操作系统路径/home/oracle/dh(用于存放外部数据文件)。GRANT ALL ON DIRECTORY ... TO user1:将目录的所有权限(读、写、执行)授予用户user1,使其能够访问该目录下的文件。外部表必须使用目录对象来定位数据文件。
备注:
- 目录对象是 Oracle 访问操作系统文件的桥梁,必须由
SYS或具有CREATE ANY DIRECTORY权限的用户创建。 - 生产环境中应仅授予
READ权限(对于外部表)或READ, WRITE(对于数据泵卸载),避免过度授权。
三、使用 ORACLE_LOADER 驱动创建外部表(CSV 文件)
1. 数据文件 emp_external.csv(与之前 SQL*Loader 所用相同)
参考文章《Oracle SQLLoader(数据加载工具)使用总结》
2. 创建外部表 EMP_EXT
sql
create table user1.EMP_ext
(
empno NUMBER(4) not null,
ename VARCHAR2(10),
job VARCHAR2(9),
mgr NUMBER(4),
hiredate DATE,
sal NUMBER(7,2),
comm NUMBER(7,2),
deptno NUMBER(2)
)
organization external
(
type oracle_loader
default directory ext_dir
access parameters
(
records delimited by newline
FIELDS TERMINATED BY ","
(
EMPNO,
ENAME,
JOB,
MGR,
HIREDATE DATE "YYYY-MM-DD HH24:MI:SS", -- 直接指定日期格式
SAL,
COMM,
DEPTNO
)
)
location('emp_external.csv')
)
reject limit unlimited;
作用:
ORGANIZATION EXTERNAL:指定为外部表。TYPE ORACLE_LOADER:使用文本加载驱动。DEFAULT DIRECTORY ext_dir:指定默认目录(数据文件所在目录)。ACCESS PARAMETERS:定义解析规则:RECORDS DELIMITED BY NEWLINE:每条记录以换行符分隔。FIELDS TERMINATED BY ",":字段由逗号分隔。- 字段列表中,
HIREDATE DATE "YYYY-MM-DD HH24:MI:SS"显式指定日期格式("直接这样指定,其它方式都报错",因为外部表中日期格式必须明确)。
LOCATION('emp_external.csv'):指定数据文件名(相对于DEFAULT DIRECTORY)。REJECT LIMIT UNLIMITED:允许无限制的拒绝记录(若限制为0,则在遇到格式错误时终止加载)。
备注:
- 外部表列定义可以包含约束(如
NOT NULL),但这些约束仅用于查询元数据,不会在数据加载时验证(除非使用REJECT LIMIT配合日志)。 - 若数据文件中有标题行,可使用
SKIP 1跳过。 - 字段顺序必须与数据文件列顺序一致;若顺序不同,可通过
POSITION指定。
四、使用预处理(Preprocessor)解压文件
场景:数据文件为压缩格式(如 .gz),需要先解压再读取。
1. 查找 zcat 命令位置
sql
SQL> host which zcat
/usr/bin/zcat
作用 :在操作系统上查找 zcat(解压压缩文件并输出到标准输出)的可执行文件路径。
2. 创建预处理目录并授权
sql
create or replace directory EXEC_DIR AS '/usr/bin';
grant read, execute on directory EXEC_DIR to user1;
作用:
- 创建目录
EXEC_DIR指向/usr/bin(存放zcat命令)。 - 授予
user1对该目录的READ和EXECUTE权限(EXECUTE允许运行其中的可执行文件)。
3. 创建使用预处理的外部表 EMP_EXT1
sql
create table user1.EMP_ext1
(
empno NUMBER(4) not null,
ename VARCHAR2(10),
job VARCHAR2(9),
mgr NUMBER(4),
hiredate DATE,
sal NUMBER(7,2),
comm NUMBER(7,2),
deptno NUMBER(2)
)
organization external
(
type oracle_loader
default directory ext_dir
access parameters
(
records delimited by newline
preprocessor ext_exec:"zcat" -- 调用预处理命令
FIELDS TERMINATED BY ","
(
EMPNO,
ENAME,
JOB,
MGR,
HIREDATE DATE "YYYY-MM-DD HH24:MI:SS",
SAL,
COMM,
DEPTNO
)
)
location('emp.csv.gz') -- 数据文件为压缩的 .gz
)
reject limit unlimited;
作用:
PREPROCESSOR ext_exec:"zcat":在读取LOCATION指定的文件前,先通过zcat解压,将解压后的内容作为输入流。- 数据文件
emp.csv.gz是压缩的 CSV 文件。 - 其他解析参数与未压缩时相同。
备注:
- 预处理程序必须位于有
EXECUTE权限的目录对象下。 - 除
zcat外,也可使用gzip -d -c、cat(对于普通文件)、sed等任何可读标准输入并输出标准输出的命令。 - 预处理功能可在外部表读取前对数据进行过滤或转换。
五、包含 LOB 字段的外部表
场景:外部数据文件包含 LOB 内容的文件名,而非 LOB 数据本身,需从其他文件读取 LOB。
1. 创建外部表 LOB_TAB_EXT(包含 CLOB 和 BLOB)
sql
create table lob_tab_ext (
number_content number(10),
varchar2_content varchar2(100),
date_content date,
clob_content clob,
blob_content blob
)
organization external
(
type oracle_loader
default directory DATA_DIR
access parameters
(
records delimited by newline
badfile DATA_DIR:'lob_tab_%a_%p.bad'
logfile DATA_DIR:'lob_tab_%a_%p.log'
fields terminated by ','
missing field values are null
(
number_content char(10),
varchar2_content char(100),
date_content char(11) date_format date mask "DD-MON-YYYY",
clob_filename char(100),
blob_filename char(100)
)
column transforms (
clob_content from lobfile (clob_filename) from (DATA_DIR) clob,
blob_content from lobfile (blob_filename) from (DATA_DIR) blob
)
)
location ('lob_test_data.txt')
)
parallel 2
reject limit unlimited;
作用:
BADFILE和LOGFILE:指定坏文件和日志文件的命名模板(%a表示代理进程号,%p表示并行度)。MISSING FIELD VALUES ARE NULL:如果某字段缺失,则用 NULL 填充。- 字段列表:
clob_filename和blob_filename为CHAR(100),用于存储文件名。
COLUMN TRANSFORMS部分:clob_content from lobfile (clob_filename) from (DATA_DIR) clob:将clob_content列定义为从clob_filename字段指向的文件读取,该文件位于DATA_DIR目录,内容类型为 CLOB。blob_content类似,类型为 BLOB。
PARALLEL 2:指定并行度为 2,可同时读取多个文件。LOCATION('lob_test_data.txt'):主数据文件,包含普通字段和 LOB 文件名。
【补充】:
COLUMN TRANSFORMS提供了强大的数据转换能力,可将文件内容、序列号、表达式值等映射到列。- 与 SQL*Loader 的
LOBFILE功能类似,但外部表方式可用于查询。
2. 简化案例(仅 CLOB)
sql
DROP TABLE my_ext_table2;
CREATE TABLE my_ext_table2 ( id NUMBER, author VARCHAR2(30), created DATE, text CLOB )
ORGANIZATION EXTERNAL (
TYPE ORACLE_LOADER
DEFAULT DIRECTORY MY_DIRECTORY
ACCESS PARAMETERS (
RECORDS DELIMITED BY 0x'0A' -- 十六进制换行符
FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '"'
( id CHAR(10),
author CHAR(30),
created DATE "YYYY-MM-DD",
fname char(100)
)
COLUMN TRANSFORMS (text FROM LOBFILE(fname) FROM (MY_DIRECTORY) )
)
LOCATION (
'loader.txt'
)
);
作用:
RECORDS DELIMITED BY 0x'0A':使用十六进制换行符(适用于某些非标准换行文件)。OPTIONALLY ENCLOSED BY '"':字段可选双引号包围。COLUMN TRANSFORMS中,text列从fname指定的 LOBFILE 读取。
备注:
COLUMN TRANSFORMS还支持FROM (DIRECTORY)指定目录;如果不指定,默认使用DEFAULT DIRECTORY。- 支持
BLOB、CLOB、NCLOB等多种 LOB 类型。 - 外部表查询时,LOB 数据在 SELECT 时才会实际读取文件,因此支持大数据量但可能影响性能。
六、使用 ORACLE_DATAPUMP 驱动生成外部表
ORACLE_DATAPUMP 驱动允许创建外部表来读取数据泵导出的二进制文件(类似于 expdp 生成的 .dmp 文件)。这种方式可用于在不同数据库之间传输数据,或作为快速数据卸载/加载的方式。
1. 通过 CREATE TABLE ... AS SELECT 生成外部表文件
sql
CREATE TABLE tab_ext_datapump
ORGANIZATION EXTERNAL
(
TYPE ORACLE_DATAPUMP
DEFAULT DIRECTORY ext_dir
LOCATION ('emp_datpump.dmp')
)
AS SELECT * FROM emp_test;
作用:
- 该语句会创建一个外部表(元数据),并同时执行
AS SELECT,将emp_test表的数据以数据泵格式写入ext_dir目录下的emp_datpump.dmp文件中。 - 这相当于将数据"卸载"到一个外部文件中,该文件可由其他数据库的外部表读取。
2. 使用已有的 .dmp 文件创建外部表(只读)
sql
CREATE TABLE tab_ext_datapump_other
(
empno NUMBER(4) not null,
ename VARCHAR2(10),
job VARCHAR2(9),
mgr NUMBER(4),
hiredate DATE,
sal NUMBER(7,2),
comm NUMBER(7,2),
deptno NUMBER(2)
)
ORGANIZATION EXTERNAL
(
TYPE ORACLE_DATAPUMP
DEFAULT DIRECTORY ext_dir
LOCATION ('emp_datpump.dmp')
);
作用:
- 创建外部表
tab_ext_datapump_other,直接引用已存在的emp_datpump.dmp文件,无需执行AS SELECT。 - 该外部表可像普通表一样查询,数据来自数据泵文件。
备注:
ORACLE_DATAPUMP外部表支持并行度、过滤、投影等操作,比ORACLE_LOADER更高效(因为文件已是二进制格式,无需解析文本)。- 常用于在不同数据库或不同环境之间快速传输表数据(特别是大表),比 CSV 更稳定、类型安全。
- 可结合
INSERT INTO ... SELECT将数据从外部表加载到普通表。
七、补充知识
1. MISSING FIELD VALUES ARE NULL
- 该选项在
ACCESS PARAMETERS中指定,表示如果记录中某个字段缺失(如 CSV 中连续两个逗号),则将该字段值设为 NULL,而不是报错。
2. 并行加载(PARALLEL)
- 在外部表定义中使用
PARALLEL n可指定并行度,让多个进程同时读取多个数据文件(需LOCATION包含多个文件),提高查询性能。
3. 拒绝限制(REJECT LIMIT)
- 设置允许的错误记录数,超过该数则查询失败。
UNLIMITED表示无限制。
4. 错误日志文件
- 可通过
BADFILE、LOGFILE、DISCARDFILE指定文件路径和命名模板,用于记录错误行、日志信息和丢弃行。
5. 外部表可用于查询,也可以用于 INSERT ... SELECT 导入普通表
- 例如:
INSERT INTO emp_table SELECT * FROM emp_ext;
6. 外部表支持分区和子分区
- 外部表可以分区,但需注意每个分区对应不同的数据文件。
7. 外部表的限制
- 只读 :不能对外部表执行
INSERT、UPDATE、DELETE(除非使用特定机制如MERGE配合外部表)。 - 性能:查询外部表性能不如普通表,因为需解析文件,但可利用并行和谓词下推优化。
8. 视图 DBA_EXTERNAL_TABLES
- 包含所有外部表的元数据(所有者、表名、类型、默认目录、访问参数、位置等)。
八、总结
外部表的两种驱动类型
| 驱动类型 | 用途 | 关键特性 |
|---|---|---|
ORACLE_LOADER |
读取文本文件(CSV、定长等) | 支持预处理、LOB 文件引用、日期/格式转换、错误记录 |
ORACLE_DATAPUMP |
读取/写入数据泵二进制文件 | 高效、类型安全、可跨数据库传输 |