OracleBulkCopy速度慢主因是服务端配置未优化:需设BatchSize为5000–10000(含CLOB时降至1000)、BulkCopyTimeout预估+缓冲,且必须禁用索引与约束、启用NOLOGGING、避免schema前缀。
OracleBulkCopy 在 .NET 6 中写入 Oracle 速度慢,不是因为框架版本问题,而是默认配置和 Oracle 服务端状态没调好。直接改 BatchSize 和 BulkCopyTimeout 能见效,但必须配合服务端动作,否则只是“治标不治本”。
BatchSize 设置多少才合理
BatchSize不是越大越快,它控制每批提交的行数,影响内存、网络和 Oracle PGA 使用:
• 过小(如 100):每百行就一次 round-trip,事务开销堆高,实测吞吐可能不到 500 行/秒
• 过大(如 50000):.net 进程内存猛涨,oracle 端容易报 ora-04030: out of process memory,尤其含 clob 或长文本列时
• 推荐起点设为 5000~10000;若单行平均超 2kb,建议降到 1000~2000
• 实际值要试:用相同数据跑三轮(2000/5000/8000),看耗时与 gc 压力变化,优先保稳
BulkCopyTimeout 必须大于预估总耗时
BulkCopyTimeout是整个操作的**总超时秒数**,不是每批超时:
• 默认 30 秒,百万级数据基本必超时
• 超时后抛 OracleException,错误信息里常含 ORA-01013: user requested cancel of current operation(注意这不是连接断开)
• 设为 0 表示无限等待,生产环境禁用;稳妥做法是预估时间 + 缓冲:比如实测 10 万行需 90 秒,设 BulkCopyTimeout = 120
• 若批量中途失败,已成功提交的批次仍会保留(前提是 BatchSize > 0)
不关索引和约束,调参数也没用
OracleBulkCopy的瓶颈常在 Oracle 服务端,.NET 侧优化收益有限:
• 必须提前执行 ALTER INDEX idx_name UNUSABLE,导入完再 REBUILD;否则每行都触发索引维护,速度降 3~5 倍
• 外键约束要临时禁用:ALTER TABLE t DISABLE CONSTRAINT fk_name,否则 bulkcopy 会隐式做参照检查
• DestinationTableName 别带 schema,例如用 "EMPLOYEES" 而非 "SCOTT.EMPLOYEES",避免权限校验延迟
• 确认表是 NOLOGGING 模式(建表时指定或运行时 ALTER TABLE t NOLOGGING),否则重做日志写满会卡住
常见空值与类型错配导致静默失败
写入中断但没明显异常?大概率是数据层校验被忽略:
• 目标列为 NOT NULL 且无默认值,但 DataTable 对应列允许 DBNull.Value → 报错 "source DataTable中该列为DBNull.Value, but target column is NOT NULL"
• 字符串往数字列写(如 "123" → NUMBER)不支持,会直接失败,OracleBulkCopy 不做类型转换
• 检查 DataTable.Columns["COL"].AllowDBNull 是否与目标列定义一致,不一致就提前 Row["COL"] = row["COL"] == DBNull.Value ? 0 : row["COL"] 补默认值
真正卡顿的地方往往不在代码里,而在 Oracle 实例那几条 ALTER 语句有没有执行、NOLOGGING 有没有生效、PGA 内存是否够用——这些比调 BatchSize 影响大一个数量级。











