SQL Server请求在本地数据库中插入200行需要20秒并不断增长

时间:2019-07-13 14:05:00

标签: c# sql-server entity-framework asp.net-core visual-studio-2019

我正在使用一个控制台应用程序(C#,asp-core 2.1,Entity Framework Core),该应用程序已连接到本地SQL Server数据库,Visual {@}提供的默认(localdb)\MSSQLLocalDB(SQL Server 2016 v13.0)工作室。

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

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

一些事实:

  • 表上没有索引
  • 我的计算机不是新的,但是我有一个很好的硬件(i7,16 Go RAM),并且插入时我的CPU利用率没有达到100%

所以,我的问题是:

  • 是否将40万行视为“大型”数据库?我以前从未使用过这么大的表,但我认为拥有这样的数据集是很常见的。
  • 我如何调查插入时间来自哪里?到目前为止,我只安装了Visual Studio(但是我可以使用其他选项)

这是有关表的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,发现请求减慢了整个过程。这是插入请求。

但是,通过查看由Entity Framework创建的SQL Request,看起来它正在进行内部联接并遍历整个表,这将解释为什么处理时间随表而增加。

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

原始请求正在执行:

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

Request View

编辑和解决方案

我最终找到了问题,这是一个愚蠢的错误:我的Id字段未声明为主键!因此,系统必须为每个插入的行遍历整个数据库。我添加了PK,现在它花了100毫秒的时间记录了200行,并且此持续时间稳定。

感谢您的时间!

2 个答案:

答案 0 :(得分:2)

我认为您可能只是缺少主键。您已经向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批处理插入。

答案 1 :(得分:0)

没有40万行不是很大。

从.NET插入大量行的最有效方法是使用SqlBulkCopy。对于400K行,这应该花费几秒钟而不是几分钟。

通过分批处理单个刀片,可以在单个事务中执行整个批处理以提高吞吐量。否则,将分别提交每个插入操作,这需要为每个插入操作同步刷新日志缓冲区到磁盘,以加强事务。

编辑:

我从您的评论中看到您正在使用实体框架。 This answer可以帮助您将SqlBulkCopy与EF结合使用。