代码之家  ›  专栏  ›  技术社区  ›  Morten Bork

当C#EF core调用一个挂起的select查询时,MSSQL management studio会很好地执行该查询。为什么?

  •  3
  • Morten Bork  · 技术社区  · 6 年前

    我不能给你足够的数据来重现错误,所以我会给你尽可能多的数据。

    我有一个select语句从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);
    

    MSSQL服务器上挂起的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]))
    

    在MSSQL management studio中执行时,此语句的执行时间为零秒(但有些毫秒)。 但是,C#应用程序会遇到超时。

    然而,原因似乎正在改变。一开始是由于IO_完成。然后它的SOS_产生了一些东西,最后是PAGEIOLATCH_SH 这是它所处的最终状态

    一、 就我个人而言,我无法理解为什么MSSQL可以毫无问题地执行查询。

    我简直没有主意了。有人能给我指出一个可能有用的方向吗?

    不。MSSQL似乎拒绝EF Core使用索引。

    根据MSSQL management studio中的执行计划,我已经完全重建了高效执行此查询所需的索引。

    任何进一步的信息,可能需要让我知道,我会看看我能做什么,尽我最大的努力。

    更新实际执行计划:

    enter image description here

    更新2: 我想指出的是,这是目前正在使用的开发,因此这个数据库,我的软件和任何介于两者之间的,是在我的“控制”。

    就我看来毫无经验的头脑所能控制的一切而言:)

    因此,任何关于如何更好地调试问题的建议,或对更多数据的请求,都将受到热烈欢迎。而且很有可能,特别是如果暗示如何提供给你!(还有我)

    SQL探查器:正在打开与数据库的连接:

    set quoted_identifier on
    set arithabort on
    set numeric_roundabort off
    set ansi_warnings on
    set ansi_padding on
    set ansi_nulls on
    set concat_null_yields_null on
    set cursor_close_on_commit off
    set implicit_transactions off
    set language us_english
    set dateformat mdy
    set datefirst 7
    set transaction isolation level read committed
    
    2 回复  |  直到 6 年前
        1
  •  3
  •   Morten Bork    6 年前

    这是我们对任何想知道我们为解决这个问题做了什么的人的回答。 解决实体框架核心事实上不允许您通过设计来实现这一点,或者通过设计来实现这一点,这是一个相当“黑客”的做法。

    我们在实际执行请求此特定数据的C#代码之前执行此存储过程。

    这不是一件好事。 1,它要求用户具有执行此操作的权限。任何应用程序都不应具有此权限级别。你可以说你想要的一切都是“可以拥有的”,但事实上,你都知道它不应该拥有。 2.
    在代码中,我在select语句之前执行一个存储过程,以使应用程序执行。真正地真正地 嗯,是的。我是。整洁吗?不,干净吗?不,我甚至不建议这样做,这里面有很多可能的陷阱,如果你改变参数,或者以任何方式改变查询,你必须重建“like”字符串。我首先使用SQL探查器来嗅探查询,然后将尽可能唯一的位复制到其他可能的查询执行中,从而构建了它。可能有不正确的身份证明吗?对 如果每秒运行select一百万次,这可能不是一个可行的解决方案。等

    但这对我很有效。

    但如果使用存储过程,则不适用于包含。 我的大脑因为试图把我的头缠在这上面而流血。所以这个痛苦的解决方案就是我正在使用的。

    /****** Object:  StoredProcedure [dbo].[WipePlanForDraftLoad]    Script Date: 11/01/2019 11:50:03 ******/
    SET ANSI_NULLS ON
    GO
    
    SET QUOTED_IDENTIFIER ON
    GO
    
    -- =============================================
    -- Author:  Morten Bork, Henrik Davidsen    
    -- Create date: 2019-01-11
    -- Description: Procedure to Wipe a cached plan for a query that sort of matches a specific string
    -- =============================================
    CREATE PROCEDURE [dbo].[WipePlanForDraftLoad]
        -- Add the parameters for the stored procedure here
    
    AS
    BEGIN
    
    declare plans cursor 
    for 
    select t1.plan_handle from sys.dm_exec_cached_plans t1
    left outer join sys.dm_exec_query_stats t2 on t1.plan_handle = t2.plan_handle
    outer apply sys.dm_exec_sql_text(sql_Handle) 
    where text like '%(@__customerCode_0 bigint,@__from_1 datetime2(7),@__to_2 datetime2(7),@__currencyCode_3 varchar(255))%WHERE (\[c\].\[currency_code\] = @__currencyCode_3) AND (\[b\].\[Id\] = \[c\].\[booking_line_id\])) AND (\[booking\].\[Id\] = \[b\].\[booking_id\])%' escape '\'
    
    declare @plan_handle varbinary(64)
    open plans
    fetch next from plans into @plan_handle
    while @@FETCH_STATUS = 0
    begin
        dbcc freeproccache(@plan_handle)
        fetch next from plans into @plan_handle
    end
    close plans
    deallocate plans
    END
    GO
    
        2
  •  0
  •   CodeMonkey    6 年前

    不久前我也遇到过类似的问题,它与在SSM中设置的某些默认值有关,EF不会自动设置这些默认值。如果可以,请尝试从代码中将EF会话的ARITHABORT设置为ON,并查看查询的执行情况是否与SSMS中的相同。