首页 > 解决方案 > SQL Server 请求在本地数据库中插入 200 行需要 20 秒并且还在增长

问题描述

我正在开发一个连接到本地 SQL Server 数据库的控制台应用程序(C#、asp-core 2.1、Entity Framework Core),这是(localdb)\MSSQLLocalDBVisual Studio 提供的默认值(SQL Server 2016 v13.0)。

我面临的问题是将数据插入表中需要很长时间。该表有 400.000 行,6 列,我一次插入 200 个。

现在,请求需要 20 秒才能执行。而且这个执行时间不断增加。考虑到我仍然有 20.000 x200 行要插入的事实,值得弄清楚这个问题来自哪里!

几个事实:

所以,我的问题是:

以下是相关表的 SQL 代码:

CREATE TABLE [dbo].[KfStatDatas] 
(
    [Id]           INT IDENTITY (1, 1) NOT NULL,
    [DistrictId]   INT           NOT NULL,
    [StatId]       INT           NOT NULL,
    [DataSourceId] INT           NOT NULL,
    [Value]        NVARCHAR(300) NULL,
    [SnapshotDate] DATETIME2(7)  NOT NULL
);

编辑 我运行 SQL Server Management Studio,我发现请求减慢了整个过程。这是插入请求。

但是,通过查看实体框架创建的 SQL 请求,它看起来像是在进行内部连接并遍历整个表,这可以解释为什么处理时间会随着表的增加而增加。

我可能会漏掉一点,但你为什么需要枚举整个表来添加行?

正在执行的原始请求:

SELECT [t].[Id] 
FROM [KfStatDatas] t
INNER JOIN @inserted0 i ON ([t].[Id] = [i].[Id])
ORDER BY [i].[_Position]

请求查看

编辑和解决方案

我最终发现了这个问题,这是一个愚蠢的错误:我的Id字段没有被声明为主键!所以系统必须为每个插入的行遍历整个数据库。我添加了 PK,现在 200 行需要 100 毫秒,并且这个持续时间是稳定的。

谢谢你的时间!

标签: c#sql-serverentity-frameworkasp.net-corevisual-studio-2019

解决方案


我认为您可能只是缺少主键。您已向 EF 声明 Id 是实体键,但您在表上没有唯一索引来强制执行此操作。

而当 EF 想要获取插入的 ID 时,没有索引,它的成本很高。所以这个查询

SELECT t.id from KfStatDatas t
inner join @inserted0 i 
  on t.id = i.id
order by i._Position

执行 38K 逻辑读取,平均耗时 16 秒。

所以试试:

ALTER TABLE [dbo].[KfStatDatas]
ADD CONSTRAINT PK_KfStatDatas
PRIMARY KEY (id)

顺便说一句,您确定这是 EF6 吗?这看起来更像是 EF Core 批量插入。


推荐阅读