Oracle 外部表(External Tables)使用总结

Oracle 外部表(External Tables)使用总结

一、外部表概述

外部表(External Table) 是 Oracle 数据库中的一种特殊表对象,它不存储数据在数据库中,而是允许数据库以只读方式访问操作系统上的文件(如 CSV、定长文本、数据泵导出文件等),将其视为数据库表进行查询,甚至可与普通表进行 JOIN、INSERT 等操作。

核心特点:

  • 数据存储在外部:数据保存在数据库外部的文件中,不占用数据库表空间。
  • 只读访问 :通常只能查询,不能对外部表执行 DML(但可通过 INSERT ... SELECT 将数据导入普通表)。
  • 两种驱动类型 :
    1. ORACLE_LOADER:用于读取文本文件(CSV、定宽等),通过访问参数解析。
    2. 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 读取/写入数据泵二进制文件 高效、类型安全、可跨数据库传输
相关推荐
长安米粒贵1 小时前
事务隔离级别选对了,为什么还是会出现丢失更新?聊聊 5 个并发误区
数据库
一条泥憨鱼1 小时前
【Redis | 黑马点评】达人探店功能源码解读
数据库·redis·缓存
赵渝强老师1 小时前
【赵渝强老师】崖山数据库的命令行客户端工具
数据库·国产数据库·yashandb·崖山数据库
忡黑梨2 小时前
PostgreSQL 小版本升级实战:14.23 升级到 14.24(源码编译方式)
数据库·postgresql
LMT流氓兔2 小时前
第五单元——第11课:自动测试“拒绝后绝不能写入”
数据库·人工智能·python·langchain
小朱爱编程1232 小时前
AI点了两次发布,我多了两篇事故
数据库·人工智能·大模型·软件工程
时间售卖铺2 小时前
MySQL DML 与 DQL 语句详解
运维·数据库·mysql·云原生
codeejun2 小时前
每日一Go·MySQL-9、索引存储结构|页分裂、页合并、索引高度与磁盘
数据库·mysql
Pniubi2 小时前
事务(Spring&MySQL)
数据库·sql·spring