實戰案例:後台公司管理列表 4000 筆資料,新增「產品更新狀態」欄位後載入超過 35 秒。經 LINQPad 分析 SQL,發現 Count(predicate) 產生複雜 CASE WHEN SQL,改用 Where(predicate).Count() 產生簡潔 WHERE 子句,速度提升百倍。
// 原始寫法:Count 帶條件 predicate
ContentStatus = Product_Maintain.Count(c => c.CompanyID == company.ID
&& c.IsDeleted == 0
&& (c.AuditStatus == 0 || c.AuditStatus == 4)) > 0 ? "產品有更新" : "";
產生 SQL (簡化):
SELECT COUNT(*) FROM (
SELECT CASE
WHEN (CompanyID = @p0 AND IsDeleted = @p1 AND (AuditStatus = @p2 OR AuditStatus = @p3)) THEN 1
ELSE 0
END AS value
FROM Company_Product_Maintain
) AS t WHERE t.value = 1
-- 執行 35 秒
// 改用 Where 先篩選再 Count
ContentStatus = Product_Maintain.Where(c => c.CompanyID == company.ID
&& c.IsDeleted == 0
&& (c.AuditStatus == 0 || c.AuditStatus == 4)).Count() > 0 ? "產品有更新" : "";
產生 SQL:
SELECT COUNT(*) FROM Company_Product_Maintain
WHERE CompanyID = @p0 AND IsDeleted = @p1 AND (AuditStatus = @p2 OR AuditStatus = @p3)
-- 執行 < 100ms
| 寫法 | LINQ to SQL 轉換策略 | SQL 特徵 | 效能 |
|---|---|---|---|
| Count(predicate) | 投影為 CASE WHEN → 外層 WHERE value=1 | 子查詢 + CASE 分支 + 外層過濾 | 掃描全表、無法有效使用索引 |
| Where(predicate).Count() | 直接轉為 WHERE 子句 | 單層 WHERE 過濾 | 索引搜尋、極快 |
| 陷阱寫法 | 優化寫法 | 說明 |
|---|---|---|
| .Where(x => x.List.Any(y => y.Id == id)) | .Where(x => x.List.Select(y => y.Id).Contains(id)) | Any 可能產生相關子查詢,Contains 可用 JOIN/IN |
| .Select(x => new { x.Id, Name = x.Child.Name }) | .Select(x => new { x.Id, x.Child.Name }) | 匿名型別屬性名稱一致可省略賦值 |
| foreach 迴圈中查詢 DB | 先 ToList() 取回記憶體再處理 | 避免 N+1 查詢 |
| .OrderBy(x => x.Date).Take(10) | 加上索引 .OrderBy(x => x.Date).Take(10) | 大表排序需索引支援 |

圖示:原始 Count(predicate) 35 秒 vs 優化後 Where().Count() 不到 100ms