【问题标题】:Entity Framework Update performance实体框架更新性能
【发布时间】:2017-08-07 21:13:35
【问题描述】:

场景:Data Transfer\Link 来自旧数据库的记录,根据我创建的新模式将实体更新到新数据库中。

您对改进这些代码有什么建议吗?我真的需要能够取得出色的表现。

提前谢谢你!

private async Task LinkCategoriesToBillingTransactions()
{
    var legacyTransactions = _legacyDb
            .TbTransactions
            .AsNoTracking()
            .Where(x => x.Id >= 1150534);

    foreach (var legacyTransaction in legacyTransactions) 
    {
        var legacyTransactionTask = _legacyDb.TbCategories
                        .AsNoTracking()
                        .SingleOrDefaultAsync(x =>
                                x.Id == legacyTransaction.CategoryId);
        var transactionTask = _cmDb.BillingTransactions
                        .SingleOrDefaultAsync(x => 
                                x.UniqueId == legacyTransaction.Guid);

        await Task.WhenAll(legacyTransactionTask, transactionTask);

        var legacyCategory = legacyTransactionTask.Result;
        var transaction = transactionTask.Result;

        if (legacyCategory == null || transaction == null)
            continue;

        var transactionCategory = await _cmDb.Categories
                         .SingleOrDefaultAsync(x => 
                                 x.UniqueId == legacyCategory.Guid);

        transaction.Category = transactionCategory;

        await _cmDb.SaveChangesAsync();
    }
}

【问题讨论】:

  • 实体框架和性能并没有真正结合在一起。
  • 如果你想要性能,我会在 SQL、MySql、Oracle 等中创建一个处理后端的过程。使用 EF 在中间数据访问层做事并想要性能就像在说:“我怎么能用这些雪鞋跑得更快?”。您可能会得到一些答案,但实际上您正在做一个 SingleOrDefault 一次只取回一个对象,所以我会更担心如果这在您连接的内容开始时很慢,以及为什么该连接在做一个时很慢对象返回。
  • 谢谢@djangojazz。也将尝试使用 sql 过程。

标签: performance linq entity-framework-6 asp.net-core-1.1


【解决方案1】:

要提高性能,您需要减少数据库往返次数。

TbCategories && 类别

您有多少个类别?可能最多 5000 个类别!

所以将它们全部加载到内存中并从中创建一个字典。

您将只进行一次往返,而不是为每个遗留事务执行一次数据库往返

var legacyCategoriesDict = _legacyDb.TbCategories.AsNoTracking().ToDictionary(x => x.Id);
var transactionCategorisDict = cmDb.Categories.ToDictionary(x => x.UniqueId);

计费交易

对于 BillingTransactions,我们不能这样做,因为您可以有数十万笔交易。

如果您可以全部加载,那很好!就像我们对类别所做的一样,否则批量加载它们。

类似的东西

legacyTransactionsList = legacyTransactions.ToList();
var legacyTransactionsCount = legacyTransactionsList.Count();

List<BillingTransaction> billingTransactions = new List<BillingTransaction>();
int batchSize = 2000; // Be careful, SQL is limited to 2100 parameters
for(int i = 0; i < 1 + (legacyTransactionsCount % batchSize); i++)
{
    var listGuid = legacyTransactionsList.Skip(i * batchSize).Take(batchSize).Select(x => x.Guid);
    var billingTransactionsToAdd = cmDb.BillingTransactions.Where(x => listGuid.Contains(x.UniqueId));
    billingTransactions.AddRange(billingTransactionsToAdd);
}

billingTransactionsDict = billingTransactions.ToDictionary(x => x.UniqueId);

您不会在一次往返中获得所有交易,但会大大提高性能。

保存更改

SaveChanges 方法为每个要保存的实体执行一次数据库往返,这非常慢。

免责声明:我是项目的所有者Entity Framework Extensions

此库不是免费的,但允许您执行所有批量操作,包括应用程序所需的 BulkUpdate:

  • 批量保存更改
  • 批量插入
  • 批量更新
  • 批量删除
  • 批量合并
  • 批量同步

例子:

// Easy to use
context.BulkSaveChanges();

// Easy to customize
context.BulkSaveChanges(bulk => bulk.BatchSize = 100);

// Perform Bulk Operations
context.BulkDelete(customers);
context.BulkInsert(customers);
context.BulkUpdate(customers);

// Customize Primary Key
context.BulkMerge(customers, operation => {
   operation.ColumnPrimaryKeyExpression = 
        customer => customer.Code;
});

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-12-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多