ASP. NET Core 3.1 Entity Framework EXISTS Продолжительность запроса - PullRequest
0 голосов
/ 09 июля 2020

Я пытаюсь профилировать запрос EF SQL в первую очередь базы данных в приложении ASP. NET Core 3.1 MVC, что, похоже, занимает немного времени.

После использования секундомера и попыток получить желаемую степень детализации, поэтому я установил MiniProfiler (замечательно, кстати, если у вас его нет, получите его).

В двух словах, функция получит запятую -Ограниченная строка идентификаторов деталей и возврат строки [] базовых идентификаторов рабочего задания;

string[] part_array = part.Split(',');
string[] base_id_array = { };

using (MiniProfiler.Current.Step("TestDB"))
{
    using (DB_Access.AccessContext db_context = new DB_Access.AccessContext())
    {
        var query = from a in db_context.WorkOrder.AsNoTracking()
                    where part_array.Contains(a.User2)
                    select new
                    {
                        a.BaseId
                    };

        if (query != null)
        {
            if (query.Any())
            {                       
                foreach (var item in query)
                {
                    Array.Resize(ref base_id_array, base_id_array.Length + 1);
                    base_id_array[base_id_array.GetUpperBound(0)] = item.BaseId;
                }
            }
        }
    }
}

MiniProfiler показывает следующее:

введите описание изображения здесь

Итак, сначала EF выполняет запрос EXIST, который занимает 147,7 мс

Затем EF закрывает соединение, повторно открывается и выполняет фактический запрос SELECT, который занимает всего 40,4 мс

Полагаю, вопрос состоит из трех:

  1. Почему EF выполняет запрос EXIST?
  2. Почему запрос выполняется так чертовски долго?
  3. Почему закрывается и открывается ли соединение в том же операторе using?

1 Ответ

1 голос
/ 09 июля 2020

Почему EF выполняет запрос EXIST?

Потому что у вас есть следующая строка в коде:

if (query.Any())

Это приведет к вашему первому запросу. Сначала материализуйте запрос и используйте результаты:

var queryResults = (from a in db_context.WorkOrder.AsNoTracking()
                where part_array.Contains(a.User2)
                select new
                {
                    a.BaseId
                })
                .ToList();
foreach (var item in queryResults)
{
    Array.Resize(ref base_id_array, base_id_array.Length + 1);
    base_id_array[base_id_array.GetUpperBound(0)] = item.BaseId;
}

Вам не нужна null проверка (потому что вы назначаете local переменной, а ToList возвращает пустой, если в базе данных результатов не найдено) и Any также (foreach сделает это за вас).

Почему запрос длится так чертовски долго?

Кажется, MiniProfiler не сообщает, сколько времени запрос принимает на сторону базы данных, он говорит, сколько времени занимает ExecuteReader. Я предполагаю, что это какой-то тестовый код, который запускается один раз, поэтому он может занять так много времени (дольше, чем выберите) из-за JIT-компиляции, а последующий вызов занимает меньше времени, потому что JIT-компиляция уже выполнена для него. Но я бы рекомендовал проверять запросы с помощью профилировщика базы данных.

...