【发布时间】:2021-12-02 06:03:23
【问题描述】:
在 .NET Core 中通过 C# 中的 Entity Framework Core 向 SQLite DB 插入记录非常慢。它比我的预期慢 10 倍。有没有提高性能的魔法?
public class MyRecord
{
[Key]
public int ID { get; set; }
public int Value { get; set; }
}
public class MyDatabase : DbContext
{
public DbSet<MyRecord> Records { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlite("Data source=mydb.db");
#if DEBUG
optionsBuilder.EnableSensitiveDataLogging(true);
#endif
}
}
public class MyDatabaseTests
{
public MyDatabaseTests()
{
var db = new MyDatabase();
db.Database.EnsureDeleted();
db.Database.EnsureCreated();
}
[TestMethod]
public void EntityFramework1000Transactions()
{
for (int i = 0; i < 1000; i++)
{
using var db = new MyDatabase();
var rec = new MyRecord
{
ID = i+1,
Value = 123456789
};
var tx = db.Database.BeginTransaction();
db.Records.Add(rec);
db.SaveChanges();
tx.Commit();
}
}
}
EntityFramework1000Transactions 在我的带有 SATA-SSD 驱动器的 PC 上需要 10 秒。替换为 eNVM 不是我的选择,因为我正在为一种具有等效存储的嵌入式系统编写应用程序。
我尝试使用db.ChangeTracker.AutoDetectChangesEnabled = false;,或者
db.BulkSaveChanges();(使用 Z.EntityFramework.Extensions.EFCore)
他们没有帮助我。
我的环境:
- Visual Studio 2019 版本 16.11.2
- .NET Core 3.1
- C#
- Microsoft.EntityFrameworkCore.Sqlite 5.0.11
- Windows 10
编辑
循环是应用程序中进程的模拟。它们不是单一的交易。 该循环旨在模拟 1000 笔交易。因此它们不能在同一个交易中。
它也不能删除事务。应用程序中的事务实际上更复杂,可以同时更新两个或多个表/记录。它必须在事务中处理。因此删除交易不是我的选择。
【问题讨论】:
-
一次添加所有记录,而不是循环。此外,无论您为每次迭代构建
MyDatabase的任何原因,都没有必要这样做。我认为解决这两个问题将大大提高性能。 -
重用上下文,删除事务并批量保存,而不是每个单独的项目。这不是魔法,只是正确使用了 EF Core
-
因此,您可能必须生成线程,而不仅仅是同步循环。我不相信在实际应用程序中你有 1000 个线程来完成这样的任务。此外,您不必启动事务,如果 SaveChanges 无法在一个 SQL 语句中执行,它会在后台执行此操作。
-
谢谢斯维亚托斯拉夫。我们的设备很少有线程并且可以相互通信。每个线程都有状态机,并且必须对电源循环安全。我最初调用单个 SaveChanges,但我了解到 DbContext 在调用 ExecuteSqlRaw 时会混淆。我还了解到,即使只更新一条记录,创建事务总是比没有事务快。
-
很难说该怎么做。 EF 增加了额外的开销,但我认为在这种情况下并不重要。无论如何测试没有 EF,只是通过 SQLiteConnection 和事务的纯 SQL。并且 SQLite 可能不适合您的情况。
标签: c# sqlite .net-core entity-framework-core