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

挑戰極限:.NET + SQL Server 4 秒導入 100 萬筆 — 規則、現狀與正確姿勢

     編輯:關於SqlServer

活動背景

社群發起「.NET + SQL Server 4 秒導入 100 萬筆」挑戰賽,規則嚴格:

  • 平台:.NET (ADO.NET),資料庫:SQL Server
  • 單表單欄位:TableB(Value1 NVARCHAR(50))
  • **禁用**預存程序、資料表值參數 (TVP) 等進階功能
  • 資料量:100 萬筆 / 測試單元
  • 硬體:2×2.0GHz CPU / 2GB RAM
  • 繳交:無 Bug、無彩蛋、無病毒的完整代碼

為什麼這是個「不公平」的挑戰?

正確的「極速導入」標準姿勢 (生產級)

1. SqlBulkCopy + IDataReader (記憶體友善、流式處理)

public class CsvDataReader : IDataReader
{
    private readonly StreamReader _reader;
    private string[] _current;
    // 實作 IDataReader 介面... (逐行讀取 CSV yield return)
}

using (var conn = new SqlConnection(cs))
using (var bulk = new SqlBulkCopy(conn))
{
    bulk.DestinationTableName = "TableB";
    bulk.BatchSize = 100000;           // 批次大小
    bulk.BulkCopyTimeout = 0;          // 無限等待
    bulk.EnableStreaming = true;      // 大物件流式
    bulk.SqlRowsCopied += (s,e) => Console.WriteLine($"已寫入 {e.RowsCopied:N0} 列");
    
    conn.Open();
    // 關鍵:最小日誌記錄需滿足條件
    // 1. 資料庫處於 Simple/Bulk-Logged 模式
    // 2. 目標表無觸發器、無 CDC、無複寫
    // 3. 使用 TABLOCK (SqlBulkCopyOptions.TableLock)
    bulk.BulkCopyOptions = SqlBulkCopyOptions.TableLock | SqlBulkCopyOptions.CheckConstraints;
    
    using (var reader = new CsvDataReader(@"D:\Data\100wan.csv"))
        bulk.WriteToServer(reader);
}

2. 資料庫端必備設定 (事半功倍)


-- 1. 切換復原模式 (大量載入期間)
ALTER DATABASE TestDB SET RECOVERY SIMPLE; -- 或 BULK_LOGGED
GO

-- 2. 目標表:無索引、無約束、無觸發器 (載入後再建)
--    若有叢集索引,資料檔**必須依叢集鍵排序**,否則分頁分裂殺效能

-- 3. 檔案群組預增長 (避免自動增長卡頓)
ALTER DATABASE TestDB MODIFY FILE (NAME = TestDB_Data, SIZE = 2GB, FILEGROWTH = 512MB);
ALTER DATABASE TestDB MODIFY FILE (NAME = TestDB_Log, SIZE = 1GB, FILEGROWTH = 256MB);
GO

3. 硬體層面:TempDB 放 SSD、資料/記錄分離、啟用瞬間檔案初始化

  • 授予 SQL 服務帳號 執行量維護工作 (SeManageVolumePrivilege) → 瞬間檔案初始化,資料檔擴容零填充。
  • TempDB 多資料檔 (核心數/8) 放最快 NVMe。

實測基準 (參考值,現代硬體)

限制影響生產環境真實做法
單欄位 NVARCHAR(50)無真實業務模型 (通常 10-50 欄位、多型別)真實寬表、大欄位、LOB
禁用預存程序 / TVP切斷最高效路徑 (SqlBulkCopy + TVP / BULK INSERT)**首選** SqlBulkCopy + DataTable/IDataReader / TVP
禁用最小日誌 / 簡單模式強制完整日誌記錄,I/O 爆增大量載入**必開**簡單/大量記錄模式 + TABLOCK
2GB RAM / 舊 CPU記憶體壓力大,緩存命中率低現代伺服器 64GB+ RAM、NVMe SSD

**結論**:在挑戰賽規則 (單執行緒、完整日誌、舊硬體) 下 4 秒極難;在**生產級最佳實踐**下,100 萬筆**遠低於 1 秒**是常態。

給挑戰者的建議

  1. 用 SqlBulkCopy + TableLock + 自訂 IDataReader (避免 DataTable 佔記憶體)。
  2. 預熱:先跑一次小批次讓 JIT 編譯、連線池建立、頁面載入緩存。
  3. 關閉防毒軟體、關閉非必要服務、設定電源計畫「高效能」。
  4. 測試前 DBCC FREEPROCCACHE; DBCC DROPCLEANBUFFERS; (僅測試環境)。
  5. **別為了挑戰而挑戰**——掌握 SqlBulkCopy 最佳實踐,才是解決真實 ETL/同步/遷移問題的鑰匙。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved
方案100 萬筆 (NVARCHAR(50))1000 萬筆 (寬表 20 欄位)關鍵點
單執行緒 SqlBulkCopy + TableLock~1.5 - 3 秒~15 - 30 秒基準線
多執行緒分區並行 (Partitioned Table + 多 SqlBulkCopy)~0.8 - 1.5 秒~8 - 15 秒CPU 密集型
BULK INSERT / bcp (本地檔案)~1 - 2 秒~10 - 20 秒繞過網路層