專案中需刪除資料表所有資料或依條件大量刪除 (如 StockCode = 'XXX'),初期使用 LINQ to SQL 內建 DeleteAllOnSubmit 發現效能極差:30 萬筆資料刪除耗時難以接受。本文分析原因並提供高效替代方案。
// 典型寫法:先查詢再刪除
var maList = ctx.T_Info_MAs.Where(c => c.StockCode == stockcode).ToList();
ctx.T_Info_MAs.DeleteAllOnSubmit(maList);
ctx.SubmitChanges();
ToList() 將 30 萬筆實體完整載入記憶體 (SELECT *),再由 SubmitChanges() 產生 30 萬條個別 DELETE 陳述式送回資料庫。DataContext 對每個實體建立追蹤快照、身分識別快取、變更集管理,記憶體與 CPU 雙重壓力。
// 直接下發單條 DELETE 陳述式,資料庫端完成過濾與刪除
ctx.ExecuteCommand("DELETE FROM T_Info_MA WHERE [STOCKCODE] = {0}", stockcode);
{0} 自動防注入,等同 sp_executesql 參數化。
// TRUNCATE TABLE:極速、最少記錄、重設身分識別種子
ctx.ExecuteCommand("TRUNCATE TABLE T_Info_MA");
| 特性 | DELETE | TRUNCATE TABLE |
|---|---|---|
| 速度 | 較慢 (逐列記錄) | 極快 (釋放資料頁) |
| 交易記錄 | 完整記錄每列刪除 | 最少記錄 (僅記錄頁釋放) |
| WHERE 條件 | 支援 | 不支援 |
| 觸發器 | 觸發 DELETE Trigger | 不觸發 Trigger |
| 身分識別種子 | 保留 | 重設為種子值 |
| 外鍵參考 | 檢查 FK 約束 | 若有 FK 參考則失敗 |
若資料表極大 (億級),單次 DELETE 或 TRUNCATE 可能導致交易記錄檔暴漲或鎖定升級。分批刪除範本:
const int BatchSize = 50000;
int deleted;
do
{
deleted = ctx.ExecuteCommand(
"DELETE TOP ({0}) FROM T_Info_MA WHERE [STOCKCODE] = {1}",
BatchSize, stockcode);
} while (deleted > 0);
TOP (N) 限制單次交易影響範圍。WAITFOR DELAY '00:00:00.100' 降低鎖定衝突。OnDeleting partial 方法、領域事件)LINQ to SQL 設計初衷是「物件導向資料操作」,大量 DML 操作並非其強項。**大量刪除/清表請毫不猶豫使用 ExecuteCommand 直通 T-SQL**,兼顧效能與簡潔。記住:TRUNCATE TABLE 是清空資料表的黃金標準;條件刪除用參數化 DELETE;超大資料量採分批策略。