You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

EF Core调用的SELECT查询在MSSQL挂起,SSMS执行正常求排查方向

EF Core查询C#应用超时但SSMS执行正常的排查方向

咱们来聊聊这个棘手的问题:同样的EF Core生成的SELECT查询,在SSMS里跑仅需数毫秒,但放到C#应用中就直接超时。查看SQL Server的SPID状态,发现它一直处于挂起状态,等待原因依次是IO_COMPLETION、SOS_YIELD_XXX,最后停留在PAGEIOLATCH_SH,而且这个问题只在特定参数(比如某个特定的CurrencyCode)下才会出现,其他参数完全正常。

问题相关代码与生成的SQL

EF Core查询代码

var bookings = context.Booking 
.Where(booking => booking.ConsigneeNumber == customer.GetCustomerTarget().Code && booking.CreatedAt >= from && booking.CreatedAt < to && booking.BookingLine.Any(b => b.BookingLineSpecification.Any(c => c.CurrencyCode == code)) )
.Include(booking => booking.BookingLine)
.ThenInclude(bl => bl.BookingLineSpecification)
.ThenInclude(bls => bls.UnitType)
.Include(booking => booking.BookingLine)
.ThenInclude(bl => bl.BookingLineAddress)
.ThenInclude(bla => bla.Country)
.Include(booking => booking.BookingLine)
.ThenInclude(bl => bl.BookingLineAddress)
.ThenInclude(bla => bla.PostalCode)
.Include(booking => booking.BookingLine)
.ThenInclude(bl => bl.BookingLineSpecification)
.ThenInclude(bls => bls.RelBookingLineSpecificationSalesInvoiceDetail)
.ThenInclude(Rel => Rel.SalesInvoiceDetail);

生成的SQL语句

(@__GetCustomerTarget_Code_0 bigint,@__from_1 datetime2(7),@__to_2 datetime2(7),@__code_3 varchar(255))
SELECT [booking].[Id], [booking].[booking_provider_id], [booking].[booking_status_id], [booking].[consignee_name], [booking].[consignee_number], [booking].[created_at], [booking].[created_by], [booking].[currency_code], [booking].[deliveryNumber], [booking].[description], [booking].[destroyed_at], [booking].[destroyed_by], [booking].[inter_company_number], [booking].[invoicee_name], [booking].[invoicee_number], [booking].[is_create], [booking].[location_id], [booking].[location_name], [booking].[maturity_level_id], [booking].[number], [booking].[order_number], [booking].[provider_key], [booking].[shipment_id], [booking].[system_responsible_id], [booking].[updated_at], [booking].[updated_by]
FROM [Integration].[booking] AS [booking]
WHERE ((([booking].[consignee_number] = @__GetCustomerTarget_Code_0) AND ([booking].[created_at] >= @__from_1)) AND ([booking].[created_at] < @__to_2)) AND EXISTS (
 SELECT 1
 FROM [Integration].[booking_line] AS [b]
 WHERE EXISTS (
 SELECT 1
 FROM [Integration].[booking_line_specification] AS [c]
 WHERE ([c].[currency_code] = @__code_3) AND ([b].[Id] = [c].[booking_line_id])) AND ([booking].[Id] = [b].[booking_id]))

已尝试的操作

  • 在Visual Studio 2017中运行测试
  • 切换到Release模式执行
  • 启用/禁用延迟加载,调整Include的使用方式
  • 重建执行计划要求的索引

排查方向建议

  • 检查参数嗅探问题:这是跨环境执行差异最常见的原因。SSMS和C#应用的连接上下文可能让SQL Server生成不同的执行计划,尤其是特定参数下。可以尝试在查询开头添加OPTION (RECOMPILE)强制重新生成计划,或者用OPTION (OPTIMIZE FOR (@__code_3 UNKNOWN))避免针对特定参数生成的“坏计划”。
  • 对比连接设置差异:虽然已经给出了应用的连接设置,但可以仔细核对SSMS的连接参数(比如SET ARITHABORT、事务隔离级别等)和C#应用的是否完全一致。细微的设置差异可能导致执行计划的选择截然不同。
  • 深挖等待类型的根因:PAGEIOLATCH_SH通常表示磁盘IO等待,意味着SQL Server在等待从磁盘读取数据页。可以检查:
    • 对应表的索引碎片情况,即使重建了索引,特定参数对应的索引页是否仍存在碎片化问题
    • 服务器的磁盘IO性能,是否在应用执行时段出现IO瓶颈
    • 内存压力:如果SQL Server内存不足,会导致频繁的页交换到磁盘,引发IO等待
  • 捕获实际执行计划对比:在C#应用执行查询时,用SQL Profiler或者Extended Events捕获实际执行计划,和SSMS中执行的计划对比,看看是否存在索引选择、扫描/查找方式的差异。
  • 验证参数类型匹配:确认EF Core传递的参数类型和SQL Server表中字段的类型完全匹配。比如currency_code如果是nvarchar类型,而EF传递的是varchar,会导致隐式转换,无法有效使用索引,进而引发性能问题。
  • 拆分查询优化复杂度:当前Include层级较多,EF Core可能生成过于复杂的单查询。可以尝试使用AsSplitQuery()将查询拆分为多个小查询,降低单查询的执行复杂度,看看是否能缓解超时问题。

内容的提问来源于stack exchange,提问作者Morten Bork

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.11 08:43:26