C# Linq To SQL 插入单个大行性能问题
Posted
技术标签:
【中文标题】C# Linq To SQL 插入单个大行性能问题【英文标题】:C# Linq To SQL insert a single big row performance issue 【发布时间】:2022-01-08 23:49:30 【问题描述】:我有一个程序使用旧的 Linq To SQL 将 ASP.NET 应用程序连接到 SQL Server DB。 ASP.NET 应用程序和 SQL Server 实例位于同一台计算机上,并且两个“环境”都已更新(IIS 10、NET Framework 4.8 和 SQL Server 2019)。
在软件中,我必须处理带有客户订单的虚拟购物车。 Cart 有很多字段,其中一个是 nvarchar 并包含“购物车文档”,通常只有几 KB,但有时可能达到几 MB(永远不会超过 10MB)
当我更新 2-3MB 范围内的文档字符串,然后更新包含它的单行时,更新操作非常非常慢(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
我不知道为什么,也不知道如何在这种情况下提高性能
--编辑: 正如建议的那样,如果我将 SQL 代码直接运行到 SQL Server 上(使用 SSMS 连接和执行代码),我已经分析了数据库上的操作并经历了相同的延迟 (~2,5) 事件。
这里是 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
【问题讨论】:
除了一些代码外,没有任何人可以帮助您。但是这个“购物车文件”到底是什么东西?一个购物车应该不过是两张桌子。 CartHeader 和 CartItems。如果您通过 LINQ 推送 10MB 字符串,我并不感到惊讶。对我来说听起来像是架构问题。 @SeanLange : 如何通过 LinqToSql 快速推送几 MB 的数据?因为让我感到惊讶的是这样做的速度很慢。我知道插入多条记录会很慢(一次执行一行),但是为什么在不涉及网络的带有 SSD 磁盘的体面服务器上传输几 MB 会很慢? 对它进行基准测试,例如在 SqlCommand 中运行直接 INSERT,这样你就知道 L2S 的错误有多大 这涉及到一个网络,除非您的应用程序与您的 sql 服务器在同一个物理机器上运行并且没有人远程连接到该应用程序。我仍然说 10mb 的购物车听起来像是一个设计问题,除非有成千上万的独特物品被购买。 @CaiusJard:好主意,刚刚在 SSMS 中测试了 linq to sql 生成的代码(对文本的简单更新)。正如我在应用程序中所经历的那样,所花费的时间为 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)的帮助下更深入地调查了 DB 分析后,发现问题可能与磁盘有关。
由于某些生产系统遇到了与我的开发机器相同的问题,我询问如何提高性能并收到了存储我的数据压缩版本的美丽提示。 数据不会太大(在我的扫描仪中),对于运行时压缩/解压缩时的内存来说太慢了,这大大减少了时间(使用了 LZMA)。 从 2,5s 到 ~0,3 是一个非常好的改进。
感谢大家的宝贵帮助和提示。
【讨论】:
以上是关于C# Linq To SQL 插入单个大行性能问题的主要内容,如果未能解决你的问题,请参考以下文章
LINQ to SQL / LINQ to Collections 性能