【问题标题】:Should I split a DbContext with multiple DbSets with hundreds of thousands of records in each of them?我应该用多个 DbSet 拆分一个 DbContext,每个 DbSet 都有数十万条记录吗?
【发布时间】:2021-09-03 19:28:07
【问题描述】:

我的问题:是什么决定了调用 DbContext.SaveChanges() 方法的速度(性能)?将所有 DbSet 放在一个 DbContext 中是不是一种不好的做法?

我有一个c#/WPF/MS SQL Server/Entity Framework Core项目,其实是针对我公司批发业务的。

我实现了一个包含数十个 DbSet 的单个 DbContext,当然,每个 DbSet 代表数据库中的一个表。大约有 10 个主要的表,分别代表订单、订单详细信息、客户、产品等,每个主要的 DbSet/表都包含大约 50,000 到 150,000 条记录。问题是当调用 DbContext.SaveChanges 方法时,它需要超过 9,000 毫秒(9 秒)才能执行!我将所有 DbSet 放在同一个 DbContext 中。这是一个坏习惯和速度慢的原因吗?

为了测试,我创建了一个单独的 DbContext 并且只在其中放置了一个 DbSet。 DbSet 有大约 100,000 条记录,但为此调用 SaveChanges 大约需要 500 毫秒,这是一个显着的改进。

鉴于我的情况,数据库性能的最佳实践是什么?请帮忙。

public class MyDbContext : DbContext
{
        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            optionsBuilder.UseLazyLoadingProxies().UseSqlServer(DbConn.GetConnStr());
            base.OnConfiguring(optionsBuilder);
        }

        public DbSet<Order> Orders { get; set; }     // This has 100k+ records.
        public DbSet<OrderDetail> OrderDetails { get; set; }     // This has 150k+ records.
        public DbSet<Ship> Ships { get; set; }               // 100k+ records
        public DbSet<ShipDetail> ShipDetails { get; set; }   // 150k+ records
        public DbSet<Customer> Customers { get; set; }     // 100k records
        public DbSet<Product> Products { get; set; }       // 10k+ records
        public DbSet<ProductStock> ProductStocks { get; set; }
        public DbSet<ProductPrice> ProductPrices { get; set; }
        public DbSet<PriceType> PriceTypes { get; set; }
        public DbSet<Claim> Claims { get; set; }
        public DbSet<Carrier> Carriers { get; set; }
        public DbSet<Channel> Channels { get; set; }
        public DbSet<Import> Imports { get; set; }
        public DbSet<ImportDetail> ImportDetails { get; set; }
}

【问题讨论】:

  • DbSet 的数量无关紧要。上下文的生命周期和您加载到其中的数据量。也许您应该提供有关这些指标的更多详细信息。
  • 我在启动时创建了一个 DbContext 实例,然后将它传递给所有类和对象。我在申请期间使用它。这会是它慢的原因吗?
  • 是的,当然。
  • 阅读:The DbContext lifetime。 DbContext 的生命周期应该很短。

标签: sql-server entity-framework-core


【解决方案1】:

不,恰恰相反。您应该在应用程序中为每个 dbContext 扩展类封装一个数据库。如果它只是一个数据库(或者更确切地说是一个模式),那么你根本不应该拆分这个类。

改为创建一个partial 类并在构成具体类的类域文件中定义不同的 dbSet。

速度基于加载的 x 项所做的更改(rly abstract...)。 更改越多,您影响/加载的行越多,事情就越难。

对您来说最大的打击是 sql 更新。当您想管理非常大的数据集时,请完全跳过将它们加载到内存中。使用 .FromSqlRaw 并在 db 级别执行所有操作,返回您需要的最小值。 例如,大规模更新就是一个很好的例子。

还要注意您正在加载不需要的对象(您未使用的关系)的情况

【讨论】:

    【解决方案2】:

    感谢 Gert Arnold、rantri 和 MKougiouris 的回复和 cmets。你们所有人都是对的。这就是我的想法。正如大家所提到的,问题不在于单个 DbContext 中包含所有表。问题是我在运行应用程序的整个生命周期中跨多个操作使用和传递我的 DbContext 的单个“实例”。这绝不应该使用 DbContext 来完成。

    我认为应该为单个工作单元或单个操作实例化 DbContext,然后在操作结束后立即处理该实例。我正在将所有数据集读入 DbContext 并使用单个 DbContext 实例进行尽可能多的查询。这是对性能缓慢的保证。

    我说过调用 SaveChanges 需要 9 秒(9,000 毫秒)将更改持久保存到数据库。现在完成相同的工作需要 250 毫秒(0.25 秒)。希望我的评论对遇到同样问题的人有所帮助。

    【讨论】:

      猜你喜欢
      • 2015-09-14
      • 2017-07-19
      • 2018-12-07
      • 2020-04-24
      • 2013-08-05
      • 2010-10-24
      • 1970-01-01
      • 2011-01-14
      相关资源
      最近更新 更多