如何使我的多对多查询更快?

Posted

技术标签:

【中文标题】如何使我的多对多查询更快?【英文标题】:How can I make my Many-to-Many queries faster? 【发布时间】:2014-02-02 08:38:34 【问题描述】:

我的应用程序中的一个页面用于显示公司过去出现的“问题”。这些问题由单个用户提交到数据库,但分配了一个或多个其他用户来处理问题,反之亦然,可以分配单个用户来处理一个或多个问题。

This 是这种关系的样子。 我的主要问题是在发出getAllProblems() 请求时,我必须检查分配给问题的所有用户,这使我在foreach 中遇到了丑陋的foreach。我的代码如下所示:

public HttpResponseMessage GetProblems(String ClientUserHash) 
         this.ClientUserHash = ClientUserHash;

          HttpResponseMessage loResponse;

          if (!CheckClientHash()) 
              SetResponseToBad(out loResponse);
           else 
              List<Int64> loFilteredObjects = PermissionsHelper.UserObjects(ClientUserID);
              var loModel = (from p in MeridianDatabase.Problems                                 
                             join o in MeridianDatabase.Objects on p.ObjectID equals o.ObjectID
                             where loFilteredObjects.Contains(o.ObjectID) && ((p.Archive == false) || (p.Archive == null))
                             select new ProblemsModel 
                                 ProblemID =     p.ProblemID,
                                 Description =   p.Description,
                                 Comment =       p.Comment,
                                 Status =        p.Status,
                                 Picture =       p.Picture,
                                 DateOpen =      p.DateOpen,
                                 DateClosed =    p.DateClosed,
                                 CategoryID =    p.CategoryID,
                                 CategoryName =  p.ProblemCategory.Name,
                                 ObjectID =      p.ObjectID,
                                 ObjectName =    p.Object.Name,
                                 EmployeeID =    p.EmployeeID,
                                 FullName =      p.Employee.Candidate.FirstName + " " + p.Employee.Candidate.LastName,
                                 CompanyName =   p.Object.Company.Name
                             ).ToList();
              foreach (ProblemsModel toProblem in loModel) 
                  var toDbUsers = MeridianDatabase.Problems.Where(x => x.ProblemID == toProblem.ProblemID).FirstOrDefault().Users;
                  if (toDbUsers.Count > 0) 
                      toProblem.ProblemUsers = new List<string>();
                      List<UsersModel> toUsersList = new List<UsersModel>();
                      foreach (User toUser in toDbUsers) 
                          toProblem.ProblemUsers.Add(String.Format("0-1", toUser.UserID, toUser.Username));
                          UsersModel toUserModel = new UsersModel() 
                              UserID = toUser.UserID,
                              Username = toUser.Username,
                              Password = toUser.Password,
                              Email = toUser.Email,
                              UserGroupsID = toUser.PermissionLevelID,
                              IsAdmin = toUser.IsAdmin,
                              LanguageID = toUser.LanguageID,
                              Name = toUser.Nickname
                          ;
                          toUsersList.Add(toUserModel);
                      
                      toProblem.Users = toUsersList;
                  
              
              loResponse = Request.CreateResponse(HttpStatusCode.OK, loModel);
          
        return loResponse;
    

我尝试使用代码内秒表并推断foreach 是罪魁祸首。我可以在不编写存储过程的情况下获得更好的性能吗?现在的情况是,获取 400 行会导致 6-9 秒的等待,这是不可接受的。

【问题讨论】:

【参考方案1】:

更改您的 loModel 以加入所有三个表。然后,您将只需要一个foreach

【讨论】:

据我了解,使用 LINQ 代码是不可行的。如果您可以提供一个代码 sn-p,那将意味着什么 - 否则,您的答案只是陈述显而易见的。【参考方案2】:

试试这样的:

from client_uo in UserObjects
join client_obj in Objects on client_uo.ObjectID == client_obj.ObjectID
join p in Problems on p.ObjectID == clt_obj.ObjectID
join pu in ProblemUsers on p.ProblemID == pu.ProblemID
join assignee in Users on pu.UserID == assignee.UserID
where client_obj.UserID == ClientUserID

这应该产生一个多重连接,让您从 ClientUserID 到 Client-UserObjects 到 ProblemObjects 到 Problems 到 ProblemUsers(受让人?)再到 Users,所有数据一次可用。您可能希望按对象、按问题或按分配的用户将其组合在一起,具体取决于您尝试生成的显示。

【讨论】:

问题是实体框架没有将 ProblemUser(见上图)视为一个单独的表,而是作为一个关系,所以我无法像访问用户和问题那样访问它.

以上是关于如何使我的多对多查询更快?的主要内容,如果未能解决你的问题,请参考以下文章

在 TypeORM 与 GraphQL 的多对多关系上使用数据加载器,查询多对多

如何在 django 中过滤查询集的多对多

从查询集中获取唯一的多对多记录列表

Mybatis的多表(多对多)查询

mysql - 来自桥接表的多对多查询[关闭]

雄辩的多对多对多 - 如何轻松加载远距离关系