LINQ 用统一语法表达过滤、投影、排序和聚合,但相同代码在内存集合与数据库查询上可能有完全不同的成本。关键是明确查询何时执行、在哪里执行以及最终需要哪些数据。

核心原则

  • IEnumerable 在进程内运行,IQueryable 通常由提供程序翻译为远程查询。
  • 在条件齐备后再 ToListAsync,让过滤和投影尽量由数据库完成。
  • 优先 Select 投影所需字段,避免加载完整实体后再丢弃大部分数据。
  • 多条件查询使用逐步组合保持可读性,并确保稳定排序后再分页。
  • 复杂表达式需检查生成 SQL;无法翻译的逻辑应明确放在物化之后。

推荐的实践步骤

可以从基础 IQueryable 开始,根据可选筛选条件逐步追加 Where,最后统一排序、投影和执行。复用规则时使用可组合表达式,而不是返回已经 ToList 的结果。对于热路径,记录生成 SQL 和执行计划,并确认条件没有因为类型转换而失去索引。

IQueryable query = db.Orders.AsNoTracking();

if (status is not null)
    query = query.Where(x => x.Status == status);

var rows = await query
    .OrderByDescending(x => x.CreatedAt)
    .Select(x => new OrderRow(x.Id, x.Total))
    .Take(50)
    .ToListAsync(cancellationToken);

示例用于说明实现思路,实际项目还应结合所使用的框架版本、部署环境和业务约束进行调整。重要配置要进入版本管理,并在测试环境验证后再发布。

常见误区

  • 过早调用 ToList 会把大量数据拉到内存后才进行筛选。
  • 在 IQueryable 中调用自定义 .NET 方法,可能无法翻译或转为低效查询。
  • 分页没有稳定的次级排序,数据变化时可能出现重复或遗漏。

上线前检查清单

  • 确认“IEnumerable 在进程内运行,IQueryable 通常由提供程序翻译为远程查询”已经通过代码审查或运行验证。
  • 确认“在条件齐备后再 ToListAsync,让过滤和投影尽量由数据库完成”已经通过代码审查或运行验证。
  • 确认“优先 Select 投影所需字段,避免加载完整实体后再丢弃大部分数据”已经通过代码审查或运行验证。
  • 确认“多条件查询使用逐步组合保持可读性,并确保稳定排序后再分页”已经通过代码审查或运行验证。
  • 为失败路径、边界条件和回滚方案准备测试或演练记录。
  • 上线后观察错误率、延迟和资源消耗,确认变化符合预期。

总结

LINQ 查询组合:写出清晰高效的数据处理代码的关键在于把隐含假设变成可执行的约束,并通过测试、监控和复盘持续验证。先从影响最大的真实场景开始,小步调整并保留回滚能力,通常比一次性大范围改造更安全,也更容易积累可复用的工程经验。