Entity Framework 更新性能
Entity Framework Update performance
场景: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();
}
}
要提高性能,您需要减少数据库往返次数。
Tb 类别 && 类别
你有多少个类别?可能最多 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 方法为每个要保存的实体执行一次数据库往返,这是 INSANELY 慢。
免责声明:我是项目的所有者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;
});
场景: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();
}
}
要提高性能,您需要减少数据库往返次数。
Tb 类别 && 类别
你有多少个类别?可能最多 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 方法为每个要保存的实体执行一次数据库往返,这是 INSANELY 慢。
免责声明:我是项目的所有者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;
});