我正在使用一个控制台应用程序(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行要插入的事实,值得弄清楚这个问题是从哪里来的!
一些事实:
所以,我的问题是:
这是有关表的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]
编辑和解决方案
我最终找到了问题,这是一个愚蠢的错误:我的Id
字段未声明为主键!因此,系统必须为每个插入的行遍历整个数据库。我添加了PK,现在它花了100毫秒的时间记录了200行,并且此持续时间稳定。
感谢您的时间!
答案 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结合使用。