Entity Framework Arithabort ВКЛЮЧЕН, но запрос все еще выполняется медленно

0

Вопрос

У меня есть простой вопрос

var count =  await _context.ExchangeRate.AsNoTracking().CountAsync(u => u.Currency == "GBP");

Таблица содержит только 3 столбца и 10 строк данных.

Когда я попытался выполнить запрос из проекта Net 5, в первый раз это заняло около 2,3 секунды, а для последующих запросов-500 мс (+- 100). Когда я выполняю тот же запрос в SSMS, он возвращается почти мгновенно (45 мс, как показано в sql profiler).

Я реализовал ARITHABORT в EF отсюда

Когда я вижу в SQL Profiler, что он устанавливает ARITHABORT, но все равно запрос занимает одинаковое время для первого запроса и последующих запросов.

sql profiler screen shot

Как мне достичь скорости, такой же, как скорость запросов SSMS. Мне нужно, чтобы запрос выполнялся очень быстро, так как в моем проекте есть требование возвращать ответ за 1 секунду (нужно сделать по крайней мере 5 простых вызовов БД...если 1 вызов занимает 500 мс, то он пересекает требование в 1 секунду)

Редактировать

Пробовал даже с ADO.Net. Время выполнения, как видно из SQL Profiler, составляет 40 мс, где, как и в случае с кодом, оно составляет почти 400 мс. Так много различий

        using (var conn = new SqlConnection(connectionString))
        {
            var sql = "select count(ExchangeRate) as cnt from ExchangeRate  where Currency = 'GBP'";

            SqlCommand cmd = new SqlCommand();

            cmd.CommandText = "SET ARITHABORT ON; " + sql;
            cmd.CommandType = CommandType.Text;
            cmd.Connection = conn;
            conn.Open();
            var t1 = DateTime.Now;
            var rd =  cmd.ExecuteReader();
            var t2 = DateTime.Now;
            TimeSpan diff = t2 - t1;

           Console.WriteLine((int)diff.TotalMilliseconds);
          
          while (rd.Read())
          {
               Console.WriteLine(rd["cnt"].ToString());
          }
            conn.Close();
        }
1

Лучший ответ

0

Ваш сценарий "первого запуска", как правило, представляет собой одноразовую статическую инициализацию DbContext. Именно здесь DbContext впервые выполняет свои сопоставления и будет выполняться при выполнении первого запроса. Типичный подход, позволяющий избежать этого для пользователя, заключается в простом запросе "прогрева", который выполняется при запуске службы.. Например, после инициализации вашей службы, просто введите что-то вроде следующего:

// Warm up the DbContext
using (var context = new AppDbContext())
{
    var hasUser = context.Users.Any();
}

Это также служит для быстрой проверки при запуске, что база данных доступна и отвечает. Сам запрос выполнит очень быструю операцию, но в это время DbContext разрешит свои сопоставления, поэтому любые вновь созданные экземпляры DbContext будут отвечать без каких-либо затрат во время запроса.

Что касается необработанной производительности, если ожидается, что это не запрос, который займет некоторое время и свяжет запрос, не делайте этого async. Асинхронные запросы не быстрее, на самом деле они немного медленнее. С помощью async запросы к DbContext направлены на обеспечение того, чтобы ваш поток веб-сервера / приложения реагировал во время обработки потенциально дорогостоящих операций с базой данных. Если вы хотите получить ответ как можно быстрее, используйте синхронный вызов.

Затем убедитесь, что все поля, по которым вы проводите фильтрацию, в данном случае Валюта, проиндексированы. Наличие поля с именем Валюта в вашей сущности в виде строки, а не идентификатора валюты FK (int) указание на запись валюты уже является дополнительным расходом на индексацию, поскольку индексы целых чисел меньше/быстрее, чем индексы строк.

Вам также не нужно беспокоиться о AsNoTracking при использовании Count запрос. AsNoTracking применяется исключительно в тех случаях, когда вы возвращаете объекты (ToList/ToArray/Single/Firstи т.д.) , Чтобы избежать того, чтобы DbContext удерживал ссылку на возвращаемую сущность. Когда вы используете Count/Any или проекция для возврата свойств из сущностей с использованием Select объект, возвращенный для отслеживания, отсутствует.

Также учитывайте задержку в сети между местом, где выполняется код вашего приложения, и сервером базы данных. Это одна и та же машина или в игре есть сетевое подключение? Как это соотносится при выполнении запроса SSMS? С помощью профилировщика вы можете увидеть, что SQL EF на самом деле отправляет в базу данных. Все остальное с точки зрения времени-это затраты: передача запроса в базу данных, Возврат полученных данных запрашивающему, анализ этого ответа. (Если в случае, когда вы возвращаете сущности, выделяете, заполняете, сверяете с существующими ссылками и т. Д... В случае подсчетов и т. Д. проверка существующих ссылок)

Наконец, чтобы обеспечить максимальную производительность, убедитесь, что время жизни ваших DbContexts сокращено. Если DbContext остается открытым и к нему было выполнено несколько запросов отслеживания (выбор сущностей без AsNoTracking) эти отслеживаемые ссылки на объекты накапливаются и могут негативно повлиять на производительность будущих запросов, даже если вы используете AsNoTracking по мере того как EF проверяет, отслеживаются ли ссылки на объекты, которые могут быть применимы/связаны с вашими новыми запросами. Много раз я видел, как разработчики предполагают, что DbContexts "дороги", поэтому они предпочитают создавать их как можно меньше, чтобы избежать этих затрат, только чтобы со временем сделать операции более дорогими.

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

2021-11-23 21:59:24

что касается вашего комментария относительно задержки в сети, как SSMS, так и сетевой код находятся на моей машине..база данных находится на сервере...и для других вещей у меня есть только один запрос (это POC). Таким образом, с той же задержкой в сети SSMS может извлекать данные за 40 мс, когда чистый код занимает 500 мс.....даже пытался с помощью ADO.ЧИСТАЯ, как видно из вопроса, и то, и другое занимает 500 мс
CrazyMonk

На других языках

Эта страница на других языках

Italiano
..................................................................................................................
Polski
..................................................................................................................
Română
..................................................................................................................
한국어
..................................................................................................................
हिन्दी
..................................................................................................................
Français
..................................................................................................................
Türk
..................................................................................................................
Česk
..................................................................................................................
Português
..................................................................................................................
ไทย
..................................................................................................................
中文
..................................................................................................................
Español
..................................................................................................................
Slovenský
..................................................................................................................

Популярное в этой категории

Популярные вопросы в этой категории