Приостановленный запрос на выборку при вызове ядром C # EF, MSSQL management studio выполняет запрос очень хорошо. Зачем? - PullRequest
0 голосов
/ 09 января 2019

Я не могу дать вам достаточно данных, чтобы воспроизвести ошибки, поэтому я собираюсь дать вам столько данных, сколько смогу.

У меня есть оператор выбора, выполняющийся из ядра EF.

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-запрос, приостановленный на сервере MSSQL, становится:

     (@__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 # испытывает тайм-аут.

Когда я использую внутренние инструменты на MSSQL, я вижу, что spid приостановлен и постоянно ожидает. Однако причина, кажется, меняется. В начале это связано с IO_COMPLETION. Затем его SOS_YIELD_ ~ что-то и, наконец, PAGEIOLATCH_SH Это окончательное состояние остается в

Я, по жизни, не могу понять, почему MSSQL может выполнить запрос без каких-либо проблем. Но EF, похоже, не в состоянии использовать индексы. Или что-то еще, чего мне не хватает полностью.

У меня просто нет идей. Кто-нибудь может указать мне направление, которое может помочь?

Я пытался:

Запуск в Visual Stuido 2017. Запуск в режиме выпуска. Я попытался включить ленивый режим, и не использовать включает. Я попытался удалить ленивые грузы и включения, просто чтобы посмотреть, смогу ли я вернуть заказы.

Неа. Кажется, MSSQL отказывает EF Core в использовании индексов.

Дело в том, что запрос зависает только тогда, когда я предоставляю определенные параметры. Остальные параметры работают просто отлично. В частности, если я предоставлю разные коды валют, это будет иметь значение для MSSQL, если запрос будет приостановлен или нет.

Я полностью перестроил индексы, необходимые для эффективного выполнения этого запроса в соответствии с планом выполнения в MSSQL management studio.

Любая дополнительная информация, которая может потребоваться, пожалуйста, дайте мне знать, и я посмотрю, что я могу сделать, в меру своих усилий.

ОБНОВЛЕНИЕ Фактический план выполнения:

enter image description here

ОБНОВЛЕНИЕ 2: Я хотел бы отметить, что это в настоящее время используется для разработки, и, таким образом, эта БД, мое программное обеспечение и все, что между ними, находится под моим «контролем».

Насколько мой явно неопытный ум может контролировать все, что угодно :)

Таким образом, любые предложения о том, как лучше отладить проблему, или запросы на дополнительные данные будут встречены с энергией и благодарностью. И, скорее всего, будет возможно, особенно если намекнуть, как это вам предоставить! (И я)

SQL Profiler: открытие соединения с БД:

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 ]

0 голосов
/ 11 января 2019

Это наш ответ для всех, кто хочет знать, что мы сделали для решения этой проблемы. Это довольно "хакерская" попытка решить тот факт, что ядро ​​платформы сущностей на самом деле не позволяет вам сделать это по своему замыслу или делает это само по себе.

Мы выполняем эту хранимую процедуру до фактического выполнения нашего кода C #, который запрашивает эти конкретные данные.

Это ищет кэшированные планы выполнения, которые можно использовать для запроса, который очень похож на тот, который генерирует EF. А потом убивает их одного за другим.

Это нехорошо. 1, он требует от пользователя иметь разрешения для этого. Ни одно приложение не должно иметь такой уровень разрешений. Вы можете утверждать, что все, что вы хотите, «могло бы иметь», но на самом деле вы все знаете, что этого не должно быть. 2
В коде я выполняю хранимую процедуру перед оператором выбора, чтобы заставить приложение выполнить. В самом деле. В самом деле? Ну да. Я. Это аккуратно? нет. Это чисто? нет. Я бы даже не рекомендовал делать это как таковое, в этом есть много возможных подводных камней, если вы измените параметры или измените запрос каким-либо образом, вам придется перестроить строку «like». Я построил его в первую очередь с помощью SQL Profiler, чтобы прослушать запрос, а затем скопировал биты, которые были настолько уникальными, насколько это возможно, для других возможных выполнений запросов. Может ли быть неправильная идентификация? Да. Если вы запускаете select миллион раз в секунду, это, вероятно, не является жизнеспособным решением. и т. д.

Но это работает для меня.

Ядро EF, выполняет свой запрос в хранимой процедуре. Но не работает с включениями, если вы используете хранимые процедуры. Мой мозг кровоточит от попыток обернуть мою голову вокруг этого. Поэтому я использую это болезненное решение.

/****** 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
0 голосов
/ 09 января 2019

Некоторое время назад у меня была похожая проблема, и она была связана с тем, что в SSMS были установлены определенные значения по умолчанию, которые EF не устанавливает автоматически. Если вы можете, попробуйте установить ARITHABORT ON для сеанса EF из кода и посмотреть, выполняется ли запрос так же, как в SSMS.

...