Замедление произвольных запросов при выполнении хранимых процедур с помощью SqlConnection в ASP Net Core - PullRequest
1 голос
/ 08 мая 2019

ОБНОВЛЕНИЕ:

Задержка доступа к данным игнорируется.Я регистрирую время выполнения вызова GetAllProductsAsync, и истекшее время стабильно.Проблема должна быть в другом месте.


У меня есть API, который возвращает список продуктов.API получает это от сервисов, в которых хранимая процедура SQL Server выполняется с использованием System.Data.SqlClient, чтобы обеспечить максимальную производительность.

Выполнение хранимой процедуры выполняется менее чем за 6 мс, а ответы API - за 20 мс.средний.Если я запускаю его локально и отправляю несколько запросов GET с помощью Почтальона (Бегун), время отклика практически одинаково для каждого запроса.

Test config

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

Полученные результаты довольно нестабильны.Шаблон в тесте 1000 запросов всегда одинаков.Один или два запроса выполняются за 20 мс, затем еще пара запросов за 500 мс.Между ними существует огромная разница.

enter image description here

Я запустил трассировку с помощью SQL Server Profiler, чтобы проверить, не связано ли замедление с базой данных.Но каждое выполнение в базе данных занимает одно и то же время, не более 2 мс.

Еще одна странная вещь - это то, что каждое выполнение базы данных выполняется с одним и тем же SPID.Похоже, что соединение всегда одинаковое, несмотря на то, что служба временная и соединение установлено.

Я думаю, что между запросами и соединением SQL может быть некоторая блокировка.Что это может быть?

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

Это мой код:

Контроллер:

namespace WebApplication1.Controllers
{
    using Microsoft.AspNetCore.Mvc;
    using System.Threading.Tasks;

    [Route("api/[controller]")]
    [ApiController]
    public class ProductController : ControllerBase
    {
        private readonly ProductService _productService;

        public ProductController(ProductService productService)
        {
            _productService = productService;
        }

        [HttpGet]
        public async Task<IActionResult> GetProducts()
        {
            var result = await _productService.GetAllProductsAsync();
            return Ok(result);
        }
    }
}

Служба (методы асинхронизации и синхронизации):

using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.Threading.Tasks;

public class ProductService
{
    private string connectionString = "xxxxx";

    public IEnumerable<Product> GetAllProducts()
    {
        var productList = new List<Product>();

        using (SqlConnection con = new SqlConnection(connectionString))
        {
            SqlCommand cmd = new SqlCommand("spGetAllProducts", con);
            cmd.CommandType = CommandType.StoredProcedure;

            con.Open();
            SqlDataReader reader = cmd.ExecuteReader();

            while (reader.Read())
            {
                productList.Add(new Product
                {
                    Id = (int)reader["Id"],
                    Name = (string)reader["Name"],
                    From = (DateTime)reader["From"],
                    To = (DateTime)reader["To"]
                });
            }
            con.Close();
        }

        return productList;
    }

    public async Task<IEnumerable<Product>> GetAllProductsAsync()
    {
        var productList = new List<Product>();

        using (SqlConnection con = new SqlConnection(connectionString))
        {
            SqlCommand cmd = new SqlCommand("spGetAllEmployees", con);
            cmd.CommandType = CommandType.StoredProcedure;

            await con.OpenAsync();
            SqlDataReader reader = await cmd.ExecuteReaderAsync();

            while (await reader.ReadAsync())
            {
                productList.Add(new Product
                {
                    Id = (int)reader["Id"],
                    Name = (string)reader["Name"],
                    From = (DateTime)reader["From"],
                    To = (DateTime)reader["To"]
                });
            }
            con.Close();
        }

        return productList;
    }
}

Запуск:

public class Startup
{
    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public IConfiguration Configuration { get; }

    // This method gets called by the runtime. Use this method to add services to the container.
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddTransient<ProductService>();
        services.AddMvc();
    }

    // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
        app.UseMvc(routes =>
        {
            routes.MapRoute(
                name: "default",
                template: "{controller=Home}/{action=Index}/{id?}");
        });
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...