C # Linq to SQL вставляет проблему с производительностью одной большой строки

#c# #asp.net #.net #sql-server #linq-to-sql

#c# #asp.net #.net #sql-сервер #linq-to-sql

Вопрос:

У меня есть программа, которая использует старый Linq для SQL для подключения ASP.NET приложение к базе данных SQL Server. ASP.NET приложение и экземпляр SQL Server находятся на одном компьютере, и обе «среды» обновлены (IIS 10, NET Framework 4.8 и SQL Server 2019).

В программном обеспечении я должен обрабатывать виртуальную корзину с заказом клиента. В корзине много полей, одно из них является nvarchar и содержит «документ корзины», который обычно составляет несколько КБ, но иногда может достигать нескольких МБ (никогда не более 10 МБ)

Когда я удаляю строку документа в диапазоне 2-3 МБ, а затем обновляю одну строку, которая ее содержит, операция udpate выполняется очень, очень медленно (2-2,5 с). Здесь обновите код :

     protected void Upsert(CartDto cart, bool isValidationUpsert = false )
    {
        lock (_sync)
        {
            if ((cart?.Id ?? 0) <= 0)
                throw new ExtendedArgumentException("cartId");

            using (var dbContext = ServiceLocator.ConnectionProvider.Instace<CartDataContext>())
            {
                var repository = new CartRepository(dbContext);
                
                var existingCart = repository.Read(crt => crt.ID == cart.Id).FirstOrDefault();
                if (existingCart == null)
                {
                    existingCart = new tbl_set_Cart();
                    existingCart.Feed(cart);

                    repository.Create(existingCart);
                }
                else
                {
                    existingCart.Feed(cart);
                    repository.Update(existingCart);
                }

                dbContext.SubmitChanges(); //<<--- This speecifi operation will take 2-2,5s previous instructions take a neglectable time
            }
        }
    }
 

Я понятия не имею, почему и как повысить производительность в этом сценарии

—ОТРЕДАКТИРОВАНО: как и предлагалось, я профилировал oepration в БД и столкнулся с тем же событием задержки (~ 2,5), если я запускаю код SQL непосредственно на SQL Server (используя SSMS для подключения и выполнения кода).

Здесь код SQL и статистика перфорации :

 DECLARE @p0 AS INT = [cart_id];
DECLARE @p1 AS INT = [entry_count];
DECLARE @p2 AS NVARCHAR(MAX) = '..document..';

UPDATE [dbo].[tbl_set_Cart]
SET [ITEMS_COUNT] = @p1, [ITEMS] = @p2
WHERE [ID] = @p0
 

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

Вот моя схема таблицы, как вы ничего не видите, это очень просто :

 /****** Object:  Table [dbo].[tbl_set_Cart]    Script Date: 02/12/2021 15:44:07 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[tbl_set_Cart](
    [ID] [int] NOT NULL,
    [AS400_CUSTOMER_COD] [nvarchar](50) NOT NULL,
    [AS400_LISTIN] [int] NOT NULL,
    [VALUE] [nvarchar](max) NOT NULL,
    [DELIVERY_COSTS] [nvarchar](max) NOT NULL,
    [ITEMS_COUNT] [int] NOT NULL,
    [ITEMS] [nvarchar](max) NOT NULL,
    [KIND] [int] NOT NULL,
    [CHECKOUT_INFO] [nvarchar](max) NOT NULL,
    [ISSUES] [nvarchar](max) NOT NULL,
    [LAST_CHECK] [datetime] NOT NULL,
    [USER_ID] [int] NOT NULL,
    [IMPERSONATED_USER_ID] [int] NOT NULL,
    [OVERRIDE_PRICES] [bit] NOT NULL,
    [HAS_ISSUE] [bit] NOT NULL,
    [IS_CONFIRMED] [bit] NOT NULL,
    [IS_COLLECTED] [bit] NOT NULL,
    [_METADATA] [nvarchar](max) NOT NULL,
 CONSTRAINT [PK_tbl_set_Cart] PRIMARY KEY CLUSTERED 
(
    [ID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
GO
 

Комментарии:

1. Ни с чем, кроме некоторого кода, нет никаких шансов, что кто-нибудь сможет вам здесь помочь. Но что это за «документ корзины»? Корзина должна состоять не более чем из двух таблиц. CartHeader и cartItems. Я не удивлен, что это может занять пару секунд, если вы перемещаете строки размером 10 МБ через LINQ. Для меня это звучит как проблема с архитектурой.

2. @SeanLange: как я могу быстро передать несколько МБ данных через LinqToSql? Потому что меня удивляет, что это медленно. Я знаю, что это медленно при вставке нескольких записей (выполнение строки одновременно), но почему передача нескольких МБ будет медленной на приличном сервере с SSD-диском, где сеть не задействована?

3. Сравните его, например, с прямым запуском ВСТАВКИ в SqlCommand, чтобы вы знали, насколько виноват L2S

4. Задействована сеть, если только ваше приложение не запущено из того же физического блока, что и ваш sql server, и никто не подключается к этому приложению удаленно. Я все еще говорю, что корзина размером 10 МБ звучит как проблема дизайна, если не приобретаются десятки тысяч уникальных товаров.

5. @CaiusJard: хорошая идея, только что протестировал сгенерированный linq to sql код (простое обновление с текстом) непосредственно в SSMS. Время, затраченное на 2,5 с, как я испытал в приложении. Похоже, что это время, которое потребуется SQL Server для обновления большой строки? как это возможно?

Ответ №1:

После более глубокого изучения профилирования БД с помощью пользователей DBA Stack Overflow (здесь обсуждение https://dba.stackexchange.com/questions/303400/sql-server-how-to-upload-big-json-into-column-performance-issue/303409#303409 ) оказывается, проблема, вероятно, связана с диском.

Поскольку какая-то производственная система столкнулась с той же проблемой, что и моя машина разработки, я спрашиваю, как повысить производительность, и получил прекрасные советы по хранению сжатой версии моих данных. Данные не слишком большие (в моем scanrio), чтобы быть слишком медленными для сжатия / распаковки в памяти во время выполнения, и это значительно сокращает время (используется LZMA). С 2,5 с до ~ 0,3 действительно хорошее улучшение.

Спасибо всем за ценную помощь и советы.