使用 EF 核心插入值会生成复杂的查询

时间:2021-06-18 12:02:36

标签: c# sql sql-server entity-framework-core

我创建了一个应用程序,可以将大约 10 万条记录插入到数据库中。我正在使用 EF 核心,例如:

context.Users.AddRange(users);
await context.SaveChangesAsync();

我希望它生成一个简单的插入查询,例如 insert into users (...) values (...)。但是,这是它产生的怪物:

SET NOCOUNT ON;
DECLARE @inserted0 TABLE (..., [_Position] [int]);
MERGE [dbo].[Users] USING (
VALUES (@p0, @p1, @p2, @p3, @p4, 0),
(@p5, @p6, @p7, @p8, @p9, 1),
(@p10, @p11, @p12, @p13, @p14, 2)

...

) AS i (..., _Position) ON 1=0
WHEN NOT MATCHED THEN
INSERT (...)
VALUES (...)
OUTPUT INSERTED.[Id], i._Position
INTO @inserted0;

它甚至没有在一个请求中包含所有项目。它多次运行查询,一次插入大约 3k 条记录。显然,这段代码真的很慢。我发现了一个类似的问题,建议设置 MaxBatchSizeUseRelationalNulls,但对我来说这些都没有帮助。即使我将 MaxBatchSize 减少到 1(这将使它运行 100k 查询),EF 仍然会生成相同的奇怪代码。如果我将 MaxBatchSize 设置为 100k,它仍然一次生成大约 3k 个项目的批次。因此,看起来 MaxBatchSize 在这种情况下实际上不起作用。

那么,有没有什么办法可以让EF Core生成更快的插入代码?

1 个答案:

答案 0 :(得分:1)

EF Core 正在尝试生成插入查询并返回生成的 ID 和其他由数据库初始化的字段,在您的情况下为 _Position。无法通过 ChangeTracker 生成插入并忘记语句。

我建议使用 linq2db.EntityFrameworkCore(免责声明:我是创作者之一)

await context.BulkCopyAsync(users);

大约 1 秒内将插入 100K 条记录。