高并发下频繁调用ToList()引发内存爆炸,应延迟执行;Where+FirstOrDefault易致N+1查询,需建索引并批量查;PLINQ不适用于I/O场景;深度分页需键集分页与复合索引配合。
高并发下频繁调用 ToList() 会立即执行查询并生成新集合,如果源数据量大或调用频次高(比如每秒数百次 Web API 请求),会导致大量短生命周期对象堆积在 Gen 0,触发高频 GC,甚至引发 OutOfMemoryException。这不是 LINQ 本身慢,而是过早物化带来的内存压力。
ToList() 或 ToArray()
IQueryable),优先保持延迟执行,用 AsEnumerable() 后再链式处理,避免重复执行 SQLMemoryCache + 懒加载,而不是每次请求都 ToList()
EF Core 中写 context.Orders.Where(o => o.UserId == userId).FirstOrDefault() 看似合理,但若 userId 来自未索引字段(如字符串 GUID 且无数据库索引),或该查询被嵌套在循环里(如遍历用户列表查各自最新订单),就会变成 N 次独立查询 —— 并发时直接压垮数据库连接池和 CPU。
CREATE INDEX IX_Orders_UserId ON Orders(UserId)
IN 批量查(context.Orders.Where(o => userIds.Contains(o.UserId))),注意 EF Core 6+ 对 Contains 的翻译更稳定SQL Server Profiler 或 EF Core 日志(EnableSensitiveDataLogging)验证最终生成的 SQL 是否符合预期AsParallel() 适合 CPU 密集型计算(如图像处理、数值聚合),但在 Web 应用中处理 HTTP 请求、DB 查询、文件读取等 I/O 操作时启用 PLINQ,反而因线程争抢、上下文切换和同步开销导致吞吐下降,响应时间波动加剧。
IEnumerable 调用 AsParallel()
ToListAsync()、ReadAsStringAsync())天然支持并发,应优先用 Task.WhenAll() 替代 PLINQThreadPool 线程,可能挤占 ASP.NET Core 的请求处理线程,造成请求排队写 query.OrderBy(x => 看似标准分页,但当跳过行数极大(如 > 50000)时,SQL Server/PostgreSQL 可能放弃使用索引,退化为全表扫描 + 排序,单次查询耗时从毫秒级飙升至秒级,并发叠加后数据库 CPU 持续 100%。
SELECT * FROM ( SELECT *, ROW_NUMBER() OVER (ORDER BY CreatedAt) AS RowNum FROM Orders ) AS T WHERE RowNum BETWEEN 10001 AND 10020
CreatedAt 和 Id,下一页查 WHERE CreatedAt > lastTime OR (CreatedAt = lastTime AND Id > lastId)
ORDER BY 字段有复合索引,例如 CREATE INDEX IX_Orders_CreatedAt_Id ON Orders(CreatedAt, Id)
EntityFrameworkCore.SqlServer 的 UseRowNumberForPaging,但仅缓解不根治,仍需索引配合实际压测中,最常被忽略的是分页方式与索引的严格匹配 —— 即使加了索引,只要 ORDER BY 和 WHERE 条件没对齐索引顺序,执行计划就可能失效。