首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

C# 使用 ODP.NET 實現百萬級資料秒級批次匯入 Oracle

     編輯:關於C語言

前言

在 .NET 應用中向 Oracle 大量寫入資料,傳統逐筆 ExecuteNonQuery 效能極差。ODP.NET (Oracle Data Provider for .NET) 提供 **Array Binding (陣列繫結)** 功能,可一次送出成千上萬筆參數化資料,達到秒級匯入百萬列。本文實測對比多種寫法,給出最佳實踐方案。

一、環境與測試基準

  • Oracle 11g/12c/19c,ODP.NET Managed Driver (NuGet: Oracle.ManagedDataAccess)。
  • 測試表:CREATE TABLE TEST_BULK (ID NUMBER, NAME VARCHAR2(50), VAL NUMBER)。
  • 目標:匯入 1,000,000 筆資料,比較耗時。

二、寫法對比與耗時 (參考值)

方法核心 API預估耗時 (100 萬筆)特點
逐筆 ExecuteNonQuerycmd.ExecuteNonQuery() 迴圈~ 30 分鐘+網路來回、解析 SQL、事務提交極慢
PL/SQL 批次 (FORALL)匿名區塊 FORALL i IN 1..N~ 15-20 秒需撰寫 PL/SQL,維護性較差
ODP.NET Array Bindingcmd.ArrayBindCount + 參數陣列~ 3-5 秒純 C#、參數化、效能最佳、支援事務
Bulk Copy (SQL Server)SqlBulkCopy~ 2-4 秒僅限 SQL Server,列舉對比

三、Array Binding 核心程式碼

using Oracle.ManagedDataAccess.Client;
using System;
using System.Data;

public static void BulkInsertArrayBinding(int rowCount = 1_000_000)
{
    const string connStr = "User Id=scott;Password=tiger;Data Source=ORCL;";
    const string sql = "INSERT INTO TEST_BULK (ID, NAME, VAL) VALUES (:id, :name, :val)";

    using (var conn = new OracleConnection(connStr))
    using (var cmd = new OracleCommand(sql, conn))
    {
        conn.Open();
        using (var tran = conn.BeginTransaction())
        {
            cmd.Transaction = tran;
            cmd.BindByName = true;            // 依參數名稱繫結
            cmd.ArrayBindCount = rowCount;    // 關鍵:指定陣列長度

            // 準備參數陣列 (陣列長度 = ArrayBindCount)
            var ids = new int[rowCount];
            var names = new string[rowCount];
            var vals = new decimal[rowCount];

            for (int i = 0; i < rowCount; i++)
            {
                ids[i] = i + 1;
                names[i] = $"Item_{i+1}";
                vals[i] = (decimal)(i * 1.5);
            }

            // 參數型別需與資料表對應
            cmd.Parameters.Add(":id", OracleDbType.Int32, ids, ParameterDirection.Input);
            cmd.Parameters.Add(":name", OracleDbType.Varchar2, names, ParameterDirection.Input);
            cmd.Parameters.Add(":val", OracleDbType.Decimal, vals, ParameterDirection.Input);

            // 單次往返完成百萬筆插入
            int affected = cmd.ExecuteNonQuery();
            tran.Commit();
            Console.WriteLine($"Inserted {affected} rows in {sw.ElapsedMilliseconds} ms");
        }
    }
}

四、關鍵參數與調優建議

  • ArrayBindCount:必須等於參數陣列長度,最大值受限於記憶體與 Oracle 限制 (建議單批 5 萬~10 萬,分批提交)。
  • BindByName = true:避免參數順序錯誤,提升可讀性。
  • 參數陣列型別:OracleDbType 需精確對應 (Int32, Varchar2, Decimal, Date 等)。
  • 事務控制:單批次包在 OracleTransaction 中,失敗全滾回;超大資料量分批提交避免 Undo 表空間爆滿。
  • FetchSize / InitialLONGFetchSize:若同步查詢大量資料,調大可減少網路往返。
  • Direct Path Load:極大量載入 (TB 級) 可考慮 OracleBulkCopy (ODP.NET 12.2+) 或外部表/ SQL*Loader。

五、分批處理範例 (避免單次記憶體過大)

const int BatchSize = 50_000;
int total = 1_000_000;
for (int offset = 0; offset < total; offset += BatchSize)
{
    int currentBatch = Math.Min(BatchSize, total - offset);
    // 填充 ids[names/vals] 陣列...
    cmd.ArrayBindCount = currentBatch;
    cmd.ExecuteNonQuery();
    tran.Commit(); // 或每 N 批提交一次
}

六、常見錯誤排查

錯誤原因解決
ORA-01008: not all variables bound參數陣列長度 != ArrayBindCount檢查陣列長度一致,且所有參數皆為陣列
ORA-01461: can bind a LONG value only for insert into a LONG columnVarchar2 長度超過欄位定義截斷字串或擴大欄位
OutOfMemoryException單批陣列過大降低 BatchSize、使用串流式寫入

七、總結

ODP.NET **Array Binding** 是 .NET 向 Oracle 大量寫入的**標準高效方案**,純 managed 程式碼、參數化防注入、支援事務、效能逼近原生工具。掌握 ArrayBindCount、參數陣列準備、分批提交三要素,即可在企業級應用中穩定實現百萬級秒級匯入。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved