我有一个文档信息的SQL表,以及一个包含这些文档的安全信息的第二个表。
有超过200万个文档行,超过600万行包含安全信息。
我需要连接安全信息并将其保存回文档表[Security]列。
目前似乎是foreach循环中的瓶颈,每个文档都会在 securityLines 列表中搜索其安全策略集合。
这是我目前的工作代码
public static Task ApplyDocumentSecurity()
{
return Task.Run(() =>
{
int totalDocCount = 0;
int take = 5000;
using (MyEntities db = new MyEntities ())
{
// get total document count
totalDocCount = db.MigrationMasters.Count();
}
for (int i = 0; i < totalDocCount; i = i + take)
{
using (MyEntities context = new MyEntities ())
{
var objectContext = (context as IObjectContextAdapter).ObjectContext;
objectContext.CommandTimeout = 3600; // 1 hour
// get the next 5,000 entries
var documents = (from d in context.MigrationMasters
where d.Security == null
select new { d.ID, d.DocNum, d.Version }).Take(take).ToList();
// get a list of the unique docnums
var uniqueDocNums = documents.Select(x => x.DocNum).Distinct();
// retrieve all the security policies for those documents
var securityLines = new List<DocumentSecurity>();
securityLines = context.DocumentSecurities
.Where(s => uniqueDocNums.Contains(s.DocNum)).ToList();
// loop through each document and get the security policies from
// the short list now in memory
List<Task> taskList = new List<Task>();
foreach (var document in documents)
{
var localCopyDoc = document;
// the below task may be running on another thread
var task = Task.Run(() =>
{
var securityLinesMatch = (from s in securityLines
where s.DocNum == localCopyDoc.DocNum && s.Version == localCopyDoc.Version
select s).ToList();
// manipulate security lines and join them, then save.
string acl = JoinSecurityLines(securityLinesMatch);
using (MyEntities context2 = new MyEntities())
{
var docToUpdate = context2.MigrationMasters.Find(localCopyDoc.ID);
docToUpdate.Security = String.IsNullOrEmpty(acl) ? "<Default>" : acl;
context2.SaveChanges();
}
});
taskList.Add(task);
}
Task.WaitAll(taskList.ToArray());
}
}
});
}
基准:
在0.84分钟内完成5,000个完成20,000个文档。在大约8分钟内完成了200,000次。所以我要等80分钟才能完成。
在0.88分钟内完成10,000份已完成的20,000份文件。所以稍微慢一点,大概是因为它有一个更大的securityLines列表来搜索每个文档。
还有另外一种方法会更快吗?我尝试在一个LINQ查询中选择文档并加入安全性,虽然它更干净,但它的速度远远低于我在这里的速度。