Более быстрое время запроса значительно увеличивается при одновременных операциях - PullRequest
0 голосов
/ 07 апреля 2020

Я создал. NET Core 3.1 API. API выполняет большую часть работы, и основная его часть выполняет SQL запросов. Большая часть API использует EF Core для доступа к данным. Однако для одного особенно важного запроса мы обнаружили, что Dapper предлагает значительное преимущество в производительности.

В одном тестируемом сценарии мы тестируем вызов API с большим количеством запросов в секунду. При линейном тестировании запросы занимают чуть меньше секунды. Однако если мы бомбардируем API с помощью 10, 15, (до 120) вызовов в секунду, производительность запроса резко падает . Например, линейные запросы занимают около 500 мс. При 15 быстрых вызовах (в течение секунды или около того) среднее время запроса составляет 3600 мс.

Это правда, что с "широким" сценарием ios эффективная пропускная способность увеличивается . Тем не менее, я не вижу, что база данных является узким местом, и мне интересно, почему запросы занимают так много времени, когда много go в течение небольшого промежутка времени.

Еще один важный момент, на который следует обратить внимание, это то, что если Я чередую вызовы нашего API, размещенного в среде, и в моем локальном окне, например, производительность и пропускная способность увеличиваются примерно на 30%. Это подтверждает достоверность теории, что сама БД не является основной проблемой. Я также обнаружил, что только этот вопрос является чем-то близким к тому, что я спрашиваю, и он сфокусирован на EF.

Dapper используется ненавязчиво. EF Context имеет типичное время жизни (область действия), хотя я экспериментировал с синглтоном и переходным процессом. Вот как это выглядит:

using (var conn = new SqlConnection(_connectionString)) //from EF properties
{
    using (var tx = await conn.BeginTransactionAsync(System.Data.IsolationLevel.ReadUncommitted))
    {
        var details = conn.QueryAsync<OurObject>(
    @"SELECT columns
    FROM table1
    INNER JOIN table2
    WHERE (someConditional = @paramValue)"
    , new
    {
        paramValue
    },tx);
        var res1 = Success((await details).ToList());
        return res1;
    }
}

Следует отметить, что нам нужно использовать этот уровень изоляции и транзакции по определенной c причине. Мы читаем из таблиц, а затем пишем им для каждого запроса. «Грязное» чтение гораздо менее важно, чем блокировки.

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

Наконец, я знаю, что это более важный вопрос, чем многие на SO, поэтому я ценю любую информацию или вещи, которые вы можете предоставить!

1 Ответ

0 голосов
/ 07 апреля 2020

Например, линейные запросы занимают около 500 мс. При 15 быстрых вызовах (в течение секунды или около того) среднее время запроса составляет 3600 мс.

...

Я не вижу, что база данных является узким местом здесь

Я могу.

Если предположить, что 500 мс - это время ЦП сервера базы данных, 15 запросов потребует 7500 мс времени ЦП. Если сервер базы данных имеет 2 ядра ЦП, он может обрабатывать 4 запроса в секунду. 15 запросов потребуют 4.5se c. Но сервер вполне способен принимать все 15 запросов одновременно (после того, как было установлено 15 отдельных клиентских сессий) и распределять по времени ЦП среди запущенных запросов. Поэтому вполне может быть, что все запросы в среднем занимают 3600 мс.

Для перспективы 5 мс это «дешевый» запрос к базе данных. Например, поиск по одной строке по ключу займет менее 1 мс процессорного времени. Для часто выполняемого запроса 500 мс - это достаточно дорого, чтобы потратить некоторое время на анализ плана запроса и оптимизацию его выполнения.

...