oraclebulkcopy 是 oracle.manageddataaccess.client 下的类,仅存在于 oracle 12.1+ 的 odp.net managed driver 中;若引用已弃用的 system.data.oracleclient 或低版本 oracle.manageddataaccess,将因类型不存在而报错。
oraclebulkcopy 不是 .net 官方支持的类,c# 中没有 oraclebulkcopy —— 这是常见误解的源头。真正可用的是 oracle 提供的 oracle.manageddataaccess.client.oraclebulkcopy,但它仅在 oracle 12.1+ 且使用 odp.net managed driver(即 oracle.manageddataaccess)时存在,且行为与 sql server 的 sqlbulkcopy 有关键差异。
为什么直接 new OracleBulkCopy() 会报错:类型未找到
错误现象:TypeLoadException 或编译提示 The type or namespace name 'OracleBulkCopy' could not be found。
根本原因:
- 你引用的是旧版
System.Data.OracleClient(已弃用、不支持 bulk copy,且 .NET Core/.NET 5+ 完全移除) - 或虽用了
Oracle.ManagedDataAccess,但 NuGet 包版本 OracleBulkCopy 类 12.1 才引入) - 或项目目标框架为 .NET Framework 4.0–4.6.1 且未启用“允许不安全代码”(该类内部使用 unsafe 操作)
✅ 正确做法:
- 安装 NuGet 包:
Oracle.ManagedDataAccess≥ 12.1.022(推荐最新稳定版,如 23.5.0) - 确认项目属性 → “生成” → 勾选
允许不安全代码(VS 中右键项目 → 属性 → 构建 → 允许不安全代码) - using 语句必须包含:
using Oracle.ManagedDataAccess.Client;
OracleBulkCopy 写入慢?检查这 4 个硬性限制
即使语法正确,百万级数据也未必“秒速”——OracleBulkCopy 实际是分批次调用 INSERT /*+ APPEND */,受 Oracle 底层机制制约:
-
DestinationTableName必须是**物理表**,不支持视图、临时表、带触发器的表(否则自动退化为逐行 INSERT) - 目标表不能有**启用的外键约束**或**启用的 CHECK 约束**(bulk 模式下 Oracle 跳过约束检查;若需校验,得先 disable,导入后再 enable)
- 源数据
DataTable或IDataReader的列顺序、类型必须与目标表**严格一致**(尤其注意NUMBER和DECIMAL映射、DATE时区处理) - 默认
BatchSize = 10000,但实际吞吐受OracleConnection的ArrayBindCount影响更大(建议显式设为 50000–100000)
示例关键设置:
var bulk = new OracleBulkCopy(connectionString) {
DestinationTableName = "T_LARGE_DATA",
BatchSize = 50000,
BulkCopyTimeout = 600
};
bulk.OracleConnection.ArrayBindCount = 80000; // ⚠️ 必须在 Open 前设置
替代方案:当 OracleBulkCopy 不可用或不达标时
如果环境受限(如老 Oracle 版本、无法禁用约束、需事务一致性),以下方案更可控:
- 用
OracleCommand+OracleParameter数组批量绑定:构造单条INSERT ALL ... SELECT * FROM TABLE(:data),配合OracleCollectionType.PLSQLAssociativeArray传入对象数组(适合 ≤ 10 万行) - 导出为 CSV,用 Oracle SQL*Loader(
sqlldr命令行工具):绕过 .NET 层,速度最快,但需服务器有执行权限和文件路径访问权 - 用
OracleDataAdapter.Update()配合UpdateBatchSize:对 DataTable 做批量 UPDATE/INSERT,兼容性好,但性能约为 BulkCopy 的 1/3–1/2
⚠️ 注意:OracleBulkCopy 不支持映射列名(无 ColumnMappings 集合),列顺序错一位就整批失败。
真正决定“秒速”的从来不是 API 名字里有没有 “Bulk”,而是 Oracle 实例的 DB_FILE_MULTIBLOCK_READ_COUNT、表空间是否为 ASSM、目标表是否 NOLOGGING、以及网络带宽是否成为瓶颈——这些比写哪行 C# 代码影响大得多。











