C# 从运行缓慢的多个数据库获取数据的方法
我有一些方法需要从多个数据库获取统计数据。关键的想法是每个表都有一个DBName,从中我深入到客户机主DB,用所需的数据库名调用存储的proc。最后,我再次向下钻取以从客户的项目数据库中获取数据 总而言之:C# 从运行缓慢的多个数据库获取数据的方法,c#,sql,algorithm,linq,linq-to-sql,C#,Sql,Algorithm,Linq,Linq To Sql,我有一些方法需要从多个数据库获取统计数据。关键的想法是每个表都有一个DBName,从中我深入到客户机主DB,用所需的数据库名调用存储的proc。最后,我再次向下钻取以从客户的项目数据库中获取数据 总而言之: 我得到了所有云用户的列表 对于每个用户,我使用其主数据库上的存储过程->标记为userClients来获取其客户机 对于每个客户机,我使用客户机项目数据库上的存储过程获取其统计信息 对于很少的数据,执行大约需要5-6秒 public List<CloudAnalysisDTO>
public List<CloudAnalysisDTO> GetCloudAnalysisForPeriod(DateTime FromDate, DateTime ToDate)
{
var users = FindAll();
List<CloudAnalysisDTO> resultsList = new List<CloudAnalysisDTO>();
HashSet<string> userclients = new HashSet<string>();
using (var db = new ProjSQLDataContext(conn))
{
foreach (var user in users)
{
if (user.ID == 0)
continue;
var ids = string.Join(",", db.UserClients.Where(uc => uc.UserId == user.ID).Select(uc => uc.ClientId.ToString()).ToArray());
var mainDB = user.MainDB;
if (mainDB.Length == 0 || ids.Length == 0)
continue;
List<CloudAnalysisDTO> userClients =
db.ExecuteQuery<CloudAnalysisDTO>(@"EXEC CloudUsersAnalysis {0},{1}", mainDB, ids).ToList<CloudAnalysisDTO>();
List<CloudAnalysisDTO> needRemove = new List<CloudAnalysisDTO>();
foreach (var client in userClients)
{
if (!userclients.Contains(user.MainDB + client.ClientID.ToString()))
userclients.Add(user.MainDB + client.ClientID.ToString());
else
{
needRemove.Add(client);
continue;
}
ClientAnalysisDTO clientAnalysisDTO =
db.ExecuteQuery<ClientAnalysisDTO>(@"EXEC CloudClientAnalysis {0},{1},{2}", client.ProjectDB, FromDate, ToDate).SingleOrDefault<ClientAnalysisDTO>();
if (clientAnalysisDTO != null)
{
client.ClientAnalysisDTO = clientAnalysisDTO;
}
client.UserID = user.ID;
client.MainDB = user.MainDB;
}
foreach (var removeDTO in needRemove)
{
userClients.Remove(removeDTO);
}
if (userClients != null && userClients.Count > 0)
resultsList.AddRange(userClients);
}
}
return resultsList;
}
公共列表GetCloudAnalysisForPeriod(DateTime FromDate,DateTime ToDate)
{
var users=FindAll();
列表结果列表=新列表();
HashSet userclients=newhashset();
使用(var db=newprojsqldatacontext(conn))
{
foreach(用户中的var用户)
{
如果(user.ID==0)
继续;
var ID=string.Join(“,”,db.UserClients.Where(uc=>uc.UserId==user.ID)。选择(uc=>uc.ClientId.ToString()).ToArray();
var mainDB=user.mainDB;
if(mainDB.Length==0 | | ids.Length==0)
继续;
列出用户客户端=
ExecuteQuery(@“execcloudusersananalysis{0},{1}),mainDB,ids.ToList();
List needRemove=新列表();
foreach(userClients中的var客户端)
{
如果(!userclients.Contains(user.MainDB+client.ClientID.ToString())
添加(user.MainDB+client.ClientID.ToString());
其他的
{
needRemove.Add(客户端);
继续;
}
ClientAnalysisDTO ClientAnalysisDTO=
ExecuteQuery(@“EXEC CloudClientAnalysis{0}、{1}、{2}”、client.ProjectDB、FromDate、ToDate).SingleOrDefault();
if(clientAnalysisDTO!=null)
{
client.ClientAnalysisDTO=ClientAnalysisDTO;
}
client.UserID=user.ID;
client.MainDB=user.MainDB;
}
foreach(needRemove中的var removeDTO)
{
userClients.Remove(removeDTO);
}
if(userClients!=null&&userClients.Count>0)
resultsList.AddRange(用户客户端);
}
}
返回结果列表;
}
我能做些什么来提高性能呢?我要做的第一件事是启用.NET跟踪,并在每次调用前后向tracelog写一行 这一行让我怀疑您可能在其中一个查询中秘密运行了一个“in”子句,这可能会导致性能下降:
var ids = string.Join(",", db.UserClients.Where(uc => uc.UserId == user.ID).Select(uc => uc.ClientId.ToString()).ToArray());
下一步,一旦您发现性能不佳的执行者(上面这一行只是我的猜测),您应该启用数据库分析,以确定哪里需要新的索引或数据库维护。对我来说,似乎有很多db调用。对我来说,也是如此,但还有其他方法吗?我不知道足够的sql技巧来实现它。也许数据库管理员所做的是每隔一段时间缓存统计数据,但我甚至不知道该怎么做。你把统计数据拉到.NET中,然后在.NET中循环。如果我没弄错的话,我现在就是这么做的。不是你不是。您正在循环调用DB。这与在一次DB调用中获取所需的所有信息,然后在.NET集合中循环不同。我在第一次存储过程中使用了“in”子句!相反,我可以做的是创建一个循环,并使用常规where从.Net中逐个获取用户客户端。但我不认为这是它运行速度慢得多的原因。这意味着调用存储过程的次数会更多,您可以在视图或单个存储过程中引用JOIN语句中的每个数据库。您只需参考databasename.schema.table,例如:“myDB.dbo.myTable”。将其放在单个过程中可以让服务器处理优化。(看起来您在一个服务器实例上,如果我错了,您需要添加一个链接服务器)。除此之外,请确保您在所加入的任何内容中引用索引字段。我不知道如何这样做,因为每个用户行都有一个不同的mainDB列。连接需要在该列的值上。所以Join[this is value]->(mainDB).dbo.myTable打开(这里是什么?)