如何优化全表更新的性能
本文关键字:更新 性能 何优化 优化 | 更新日期: 2023-09-27 18:17:29
我正在围绕斯坦福大学的Folding@Home项目编写一个相当大的服务。项目的这一部分是托管在Windows服务中的WCF服务。使用适当的数据库索引和双核Core2Duo/7200rpm盘片,我能够每秒运行大约1500行(SQL 2012数据中心实例)。当我运行此更新时,每小时都要花费相当多的时间来遍历所有150万用户并在必要时添加更新。
查看SQL Server Management Studio 2012中的性能分析器,我看到每个用户都是通过单独的查询加载的。EF是否有一种方法可以急切地加载一组给定大小的用户,在内存中更新它们,然后保存更新后的用户——使用比单次选择、单次更新更优雅的查询?我目前使用EF5,但如果我需要移动到6来提高性能,我会的。此进程延迟的主要原因是等待数据库结果。
此外,如果有什么我应该改变的ForAll或预处理,请随时提出来。组预处理非常快,通过控制每个EF上下文的大小,极大地提高了更新的速度——但如果我可以预处理更多,并改善整体时间,我非常愿意研究它!
private void DoUpdate(IEnumerable<Update> table)
{
var t = table.ToList();
var numberOfRowsInGroups = t.Count() / (Properties.Settings.Default.UpdatesPerContext); //Control each local context size. 120 works well on most systems I have.
//Split work groups out of the table of updates.
var groups = t.AsParallel()
.Select((update, index) => new {Value = update, Index = index})
.GroupBy(a => a.Index % numberOfRowsInGroups)
.ToList();
groups.AsParallel().ForAll(group =>
{
var ents = new FoldingDataEntities();
ents.Configuration.AutoDetectChangesEnabled = false;
ents.Configuration.LazyLoadingEnabled = true;
ents.Database.Connection.Open();
var count = 0;
foreach (var a in group)
{
var update = a.Value;
var data = UserData.GetUserData(update.Name, update.Team, ents); //(Name,Team) is a superkey; passing ents allows external context control
if (data.TotalPoints < update.NewCredit)
{
data.addUpdate(update.NewCredit, update.Sum); //basic arithmetic, very quick - may attach a row to the UserData.Updates collection. (does not SaveChanges here)
}
}
ents.ChangeTracker.DetectChanges();
ents.SaveChanges();
});
}
//from the UserData class which wraps the EF code.
public static UserData GetUserData(string name, long team, FoldingDataEntities ents)
{
return context.Users.Local.FirstOrDefault(u => (u.Team == team && u.Name == name))
?? context.Users.FirstOrDefault(u => (u.Team == team && u.Name == name))
?? context.Users.Add(new User { Name = name, Team = team, StartDate = DateTime.Now, LastUpdate = DateTime.Now });
}
internal struct Update
{
public string Name;
public long NewCredit;
public long Sum;
public long Team;
}
EF不是原始性能的解决方案…这是实现数据访问层(DAL)的"简单方法",但会带来相当大的开销。我强烈建议使用Dapper或raw ADO。. NET进行批量更新…会快得多。
http://www.ormbattle.net/现在,为了回答你的问题,要在EF中进行批量更新,你需要下载一些扩展和第三方插件来启用这些功能。参见:批量更新/删除EF5