SQL*Loader是批量导入工具,外部表是只读数据库对象,用于实时查询文件;二者机制不同,不可互换。创建外部表需确保DIRECTORY权限、本地文件路径、字符集一致;定义时注意FIELDS TERMINATED BY、OPTIONALLY ENCLOSED BY、MISSING FIELD VALUES ARE NULL和REJECT LIMIT等关键参数。
SQL*Loader 和外部表不是一回事,别混用
sql*loader 是一个命令行工具,用于把文件数据批量导入数据库表;而外部表是 oracle 提供的一种数据库对象,它让 select 语句能像查普通表一样读取操作系统上的文件。两者底层机制不同,不能“用 sql*loader 创建外部表”,也不能“用 sql*loader 直接查询”——这是最常见的误解源头。
真正想实现“PL/SQL 直接查询文件数据”,必须建外部表,然后在 PL/SQL 中用 SELECT 或游标访问。SQL*Loader 只负责一次性加载,不提供运行时查询能力。
创建外部表前必须确认的三件事
外部表依赖 Oracle 的目录对象(DIRECTORY)来定位文件路径,且对权限、格式、字符集极其敏感。漏掉任意一项都会导致 ORA-29913 或 ORA-29400 错误。
-
CREATE DIRECTORY必须由 DBA 执行,且对应的操作系统路径需被 Oracle 用户(如 oracle)实际可读 —— 单纯有 OS 权限不够,Oracle 进程用户也得能打开那个文件 - 文件必须放在数据库服务器本地(不是客户端),且不能是网络挂载盘(除非已明确配置为支持)
- 字符集要和数据库一致,否则字段截断或乱码;推荐显式指定
CHARACTERSET AL32UTF8(或对应数据库字符集)
外部表定义里最容易写错的参数
建外部表时,ORGANIZATION EXTERNAL 子句里的参数顺序和含义容易混淆,尤其是 ACCESS PARAMETERS 块内的字段分隔与空值处理逻辑。
-
FIELDS TERMINATED BY ','后面如果没加OPTIONALLY ENCLOSED BY '"',遇到带逗号的文本字段会直接解析错行 - 默认不识别空字符串为 NULL,需显式写
MISSING FIELD VALUES ARE NULL,否则空列会被当成缺失字段报错 -
REJECT LIMIT UNLIMITED要加上,否则第一行格式不对就整个查询失败,而不是跳过坏行 - 示例片段:
ORGANIZATION EXTERNAL ( TYPE ORACLE_LOADER DEFAULT DIRECTORY my_dir ACCESS PARAMETERS ( RECORDS DELIMITED BY NEWLINE CHARACTERSET AL32UTF8 BADFILE my_dir:'data.bad' DISCARDFILE my_dir:'data.dis' FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '"' MISSING FIELD VALUES ARE NULL REJECT LIMIT UNLIMITED ) LOCATION ('data.csv') )
PL/SQL 中查外部表和普通表没区别,但要注意执行上下文
外部表可以出现在任何标准 SQL 场景中:游标、SELECT INTO、视图封装、甚至物化视图日志里(虽然不推荐)。但它的执行本质是每次查询都重新读文件,所以性能和一致性行为完全不同。
- 外部表没有统计信息,优化器默认按 100 行估算,复杂 JOIN 容易走错执行计划;必要时可用
/*+ DYNAMIC_SAMPLING(4) */提示 - 文件内容在查询执行期间被修改(比如被另一个进程覆盖),可能导致单次查询返回部分旧数据、部分新数据,不保证事务一致性
- 不能对外部表做
INSERT/UPDATE/DELETE,也不能建索引或约束 —— 它只是个只读通道 - 在存储过程中调用,只要当前用户有
SELECT权限即可,不需要额外授权给目录对象(权限已在建表时绑定)










