Выполнение StoredProcedure занимает невероятное количество времени в EF6

Я использую EF6 (v6.2.0) в ASP.NET MVC5.

При выполнении определенной StoredProcedure через функцию EF6 SqlQuery () мне приходится ждать около 2 минут (!), Чтобы получить результат в памяти.

StoredProcedure занимает около 9-12 секунд в базе данных из-за некоторых сложных вычислений и вызывается с 11 параметрами:

exec sp_Calculation @q, @y, @gn, @gesa, @rg, @cl, @yc, @vlv, @vlb, @ugv, @ugb

Результат - около 2,1 МБ данных (~ 9000 строк, 49 столбцов).

Общее время выполнения: 00:00:11.711

В коде я называю это так:

dbContext.Database.Log = s => Trace.Write(s);
return await dbContext.Database.SqlQuery<CalculationResult>("exec sp_Calculation @q, @y, @gn, @gesa, @rg, @cl, @yc, @vlv, @vlb, @ugv, @ugb", parameters).ToListAsync(token);

След:

exec sp_Calculation @q, @y, @gn, @gesa, @rg, @cl, @yc, @vlv, @vlb, @ugv, @ugb

-- @q: 'null' (Type = Int32, IsNullable = false)
-- @y: '1101' (Type = Int16, IsNullable = false)
-- @gn: 'null' (Type = Int32, IsNullable = false)
-- @gesa: '1' (Type = Byte, IsNullable = false)
-- @rg: 'null' (Type = Int32, IsNullable = false)
-- @cl: '4' (Type = Byte, IsNullable = false)
-- @yc: '17' (Type = Int16, IsNullable = false)
-- @vlv: 'null' (Type = Int16, IsNullable = false)
-- @vlb: 'null' (Type = Int16, IsNullable = false)
-- @ugv: 'null' (Type = Int16, IsNullable = false)
-- @ugb: 'null' (Type = Int16, IsNullable = false)
-- Executing asynchronously at 19.07.2018 18:27:23 +02:00
-- Completed in 114479 ms with result: SqlDataReader

Мое первое предположение было узким местом в сети, но вызов StoredProc на веб-сервере через SSMS также выполняется очень быстро. Итак, сеть не должна быть проблемой.

Вот стек вызовов от dotTrace с большим узким местом: Выполнение StoredProcedure занимает невероятное количество времени в EF6 Что странно, так это чрезвычайно долгое время выполнения нативных сборок.

Может кто-нибудь уточнить, что именно там происходит и как решить проблему?

Обновлено: Я только что нашел вопрос с похожей проблемой и постараюсь узнать о нем больше. Может это является сеть.

Обновлено еще раз: Мне нужны все данные в памяти из-за некоторой предварительной обработки перед созданием из него файла csv. Похоже, что узким местом является SNINativeMethodWrapper. Мне не нужна помощь для выполнения моей задачи с другими библиотеками. Я просто хочу, чтобы данные быстрее помещались в память.

ORM не предназначены для запросы отчетов. Ожидание возврата 9К строк, их преобразования в список и их использования тогда тоже происходит медленно и, вероятно, приводит к большому количеству перераспределений. Используйте IEnumerable, чтобы начать обработку результатов по мере их поступления. В конце концов, для отчета или экспорта вам не нужны все данные, вы можете начать записывать результаты, как только появится первая строка.

Panagiotis Kanavos 20.07.2018 09:56

Вы также можете использовать микроОРМ, например Dapper. Поскольку вы не имеете дело с объектами, вам не нужно отслеживать изменения, поддержку обновлений и все другие функции, которые предоставляет полная ORM. Просто сопоставление строк DbDataReader с объектами CalculationResult

Panagiotis Kanavos 20.07.2018 09:58

Мы используем EF6 во всем приложении и практически все его функции. Так что замена - это не вариант прямо сейчас. Дело в том, что после загрузки данных будет еще немного обработки. Но сама загрузка занимает столько времени. Учитывает ли EF6 выделение объектов при отображении времени, затраченного на трассировку?

cmxl 20.07.2018 10:22

это не причина использовать функции неправильный. SO тоже использует EF. И Даппер. Я думаю, что ADO.NET тоже там, где это необходимо. ORM по-прежнему не подходят для отчетов об экспортных запросах

Panagiotis Kanavos 20.07.2018 11:32

Обычный ADO.NET дает те же результаты, поэтому с EF6 это не проблема. Некоторые нативные вещи кажутся сумасшедшими, но мне нужно знать, что именно здесь не так.

cmxl 21.07.2018 18:20

тогда это сама хранимая процедура. Вы не предоставили никакой соответствующей информации, поэтому помочь невозможно. Соответствующая информация - это сам код, план выполнения, схемы таблиц и индексы. Используйте Activity Monitor SQL Server, чтобы увидеть, что на самом деле происходит, есть ли какие-либо блокировки, блокировки

Panagiotis Kanavos 23.07.2018 09:18
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
6
90
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

У меня была такая же проблема, и SSMS вне курса будет выполняться быстрее.

Проблема в том, что все записи назначаются соответствующему объекту POCO и его свойствам, он перебирает каждое значение до тех пор, пока не будет получен огромный набор объектов.

Что я сделал для решения проблемы:

Я создал разбивку на страницы в sproc (подкачка уровня sql). Никто не может просматривать 9000+ записей одновременно, если вы не являетесь CYBORG. Так что просто получите 10-100 записей из набора результатов при выполнении процедуры сохранения.

Обновлено:

Если вам нужно получить набор результатов для создания Excel, я бы предложил возможные способы сделать это:

  • Создайте файл Excel прямо из sql, взяв набор результатов переход от db к C# занимает много времени.
  • Если он вам все еще нужен на стороне сервера тогда я бы посоветовал вам использовать EPPlus или любой другой ухоженный сторонние библиотеки для создания Excel для вас на сторона сервера (EPPlus - это то, что я использую и для меня это не займет больше 5 секунд, исключая выполнение SP время)
  • Обратное переключение на ado.net для создания отчетов возможно из-за разницы представление между EF и ADO.
  • Оптимизируйте свой запрос, уточните его.
  • Если ваши руки по-прежнему связаны клиентом, то несите время загрузки, которое вы испытываете в данный момент;)

Таким образом, распределение может быть узким местом. Это то, что ты имеешь в виду? Я знаю, что никто не может их просмотреть, но нашему клиенту они нужны все сразу. Пейджинг означал бы, что мне пришлось бы снова и снова выполнять вычисления для каждой страницы. каждый из которых занимает 9-12 секунд. К сожалению, сохраненная процедура не может быть изменена

cmxl 20.07.2018 10:16

@cmxl да. Пейджинг обычно добавляет максимум 1-2 секунды, в моем случае я почти не заметил разницу во времени. Во-вторых, попробуйте убедить своих клиентов использовать разбиение на страницы, если только клиент не использует набор результатов для создания отчета в формате Excel.

IteratioN7T 20.07.2018 10:58

это действительно превосходно: '(

cmxl 20.07.2018 11:00

Спасибо вам за ваши предложения! Я добавил свой вопрос со ссылкой на очень похожую проблему, которую я вижу в результате dotTrace. Я просто попробовал это с простым старым ADO.NET, и, к сожалению, он работал так же медленно, как EF6.

cmxl 20.07.2018 11:30

@cmxl означает, что хранимая процедура работает медленно и передает слишком много данных. Что касается Excel, EPPlus может генерировать лист Excel из DbDataReader с sheet.FromDataReader(). Вам не нужно читать все, прежде чем приступить к созданию листа.

Panagiotis Kanavos 20.07.2018 11:31

@cmxl, к сожалению, EF построен поверх ADO, поэтому, если это не имеет значения, вам нужно пересмотреть свой sp.

IteratioN7T 20.07.2018 11:47

Также будьте осторожны с разбиением на страницы, потому что order by вместе с top или использование FETCH FIRST и OFFSET (которое также использует order by) работает как фильтр. Если ваш заказ не является абсолютным, вы можете потерять строки при определенных условиях. Например, при настройке 30 строк на страницу строка №31 не будет отображаться на странице (правильно), но если эта строка получит позицию №30 (может произойти без изменений данных, если порядок не является абсолютным), при следующем выполнении запроса будет получено page # 2 он также не будет отображаться на странице # 2.

Stefanos Zilellis 20.07.2018 17:00
Ответ принят как подходящий

Проблема заключалась в большой нагрузке между базой данных и связанными серверами. Собственному API было трудно протолкнуть весь набор записей через сетевой интерфейс SQL. Так что с самим кодом проблем нет.

Все работает так быстро, как ожидалось, когда нагрузка между связанными серверами была низкой.

Другие вопросы по теме