我有以下方法,我正在尝试优化。目前,该方法工作很好,然而,它需要3个多小时才能完成。我觉得,使用一些巧妙的LINQ连接,它应该能够在几分钟内运行。以下是一种方法:
public async Task UpdateEmailTable(IEnumerable students)
{
Console.WriteLine("Updating Email table");
var studentEmails = students.ToList();
int totalStudents = studentEmails.Count;
int currentCount = 0;
float lastPercentage = -1;
foreach (var student in studentEmails)
{
var isIn = await _context.BarcDemoGraphicEmail.AnyAsync(z => z.Sridentifier == student.StudentId);
if (!isIn)
{
var ar = await _context.Barcaccount.FirstOrDefaultAsync(z => z.SrIdentifier == student.StudentId);
await _context.BarcDemoGraphicEmail.AddAsync(new BarcDemoGraphicEmail
{
Sridentifier = student.StudentId,
Email = student.EmailAddress,
Updatedate = DateTime.Now,
Aridentifier = ar == null ? "" : ar.ArIdentifier
});
}
else
{
var rec = await _context.BarcDemoGraphicEmail.Where(z => z.Sridentifier == student.StudentId)
.FirstAsync();
rec.Email = student.EmailAddress;
rec.Updatedate = DateTime.Now;
}
await _context.SaveChangesAsync();
int percentage = (int)Math.Round((float)currentCount / totalStudents * 100);
if (lastPercentage != percentage) Console.Write("\r" + percentage + "%");
lastPercentage = percentage;
currentCount++;
}
}
因此,这个方法是通过学生ids和电子邮件列表调用的。此列表不来自数据库。此列表来自web调用,必须传递到方法中。然后,它遍历列表,一次一个。它接受学生的id,并通过设置BarcDemoGraphicEmail
标志来检查它是否存在于isIn
表中。
如果学生ID不在BarcDemoGraphicEmail
表中,它将从另一个名为BarcAccount
的表中提取帐户信息。然后,它使用来自BarcDemoGraphicEmail
表的信息和来自students
当前迭代的电子邮件将学生的电子邮件插入到D7
中。
如果学生ID位于BarcDemoGraphicEmail
表中,它只需提取该记录并从当前迭代中更新UpdateDate
字段和Email
字段。
正如我前面说过的,这个方法目前运行良好,但是它花费的时间太长了。我如何优化我的代码(或者可能优化数据库),使其执行得更快?
这是一个使用EntityFrameworkCore3.1的控制台.NET Core3.1 C#应用程序。数据库是Server数据库。
发布于 2020-12-15 08:30:56
一些简短的评论:
DemoGraphic
不是一个复合词,所以中间不应该有大写字母。然而,Barcaccount
是如此,它应该被称为BarcAccount
。Sridentifier
,Updatedate
,Aridentifier
也一样。ar
是什么,或者sr
。UpdateEmailTable(IEnumerable students)
和var studentEmails = students.ToList();
使用正确命名和类型的参数。您的方法需要一个List studentEmails
(或者ICollection studentEmails
),这样编写它,并使调用代码传递正确的参数。Console.WriteLine
。这意味着它混合了业务逻辑和UI。馊主意。至少将其更改为使用日志系统,然后将其配置为将其输出到命令行。您说这需要三个小时,这表明要么是大量的数据,要么是特别慢的代码(或者您的表没有正确地编入索引?)也许使用SqlBulkInsert的实现逻辑可以解决性能问题。也许将传入的数据存储在一个表中,然后应用一两个SQL查询来更新BarcDemoGraphicEmail中的数据。
发布于 2020-12-15 04:25:37
您可以在相同的循环迭代中查询同一BarcDemoGraphicEmail
表两次。
您可以如下所示改进查询
var rec = await _context.BarcDemoGraphicEmail
.FirstOrDefaultAsync(z => z.Sridentifier == student.StudentId);
if (rec == null)
{
var ar = ...
...
}
else
{
rec.Email = student.EmailAddress;
rec.Updatedate = DateTime.Now;
}
此外,还应该将.ConfigureAwait(false)
添加到所有异步方法中。
https://codereview.stackexchange.com/questions/253464
复制相似问题