简体   繁体   English

MySQL查询优化:多个SELECT IN到LEFT JOIN

[英]MySQL query optimization: Multiple SELECT IN to LEFT JOIN

I usually go with the join approach but in this case I am a bit confused. 我通常采用join方法,但在这种情况下我有点困惑。 I am not even sure that it is possible at all. 我什至不确定这是否有可能。 I wonder if the following query can be converted to a left join query instead of the multiple select in used: 我想知道以下查询是否可以转换为left join查询,而不是使用的多select in查询:

select 
   users.id, users.first_name, users.last_name, users.description, users.email 
from users 
where id in (
     select assigned.id_user from assigned where id_project in (
            select assigned.id_project from assigned where id_user = 1
                                                               )
            ) 
   or id in (
     select projects.id_user from projects where projects.id in (
            select assigned.id_project from assigned where id_user = 1
                                                                )
            )  

This query returns the correct result set. 该查询返回正确的结果集。 However, I guess the repetition of the query that selects assigned.id_project is a waste. 但是,我猜选择选择assigned.id_project的查询的重复是浪费的。

You could start with the project assignments of user 1 a1 . 您可以从用户1 a1的项目分配开始。 Then find all assignments of other people to those projects a2 , and the user in the project table p . 然后在项目表p找到其他人对那些项目a2和用户的所有分配。 The users you are looking for are then in either a2 or p . 然后,您要查找的用户位于a2p I added distinct to remove users who can be reached in both ways. 我添加了distinct,以删除可以通过两种方式访问​​的用户。

select  distinct u.*
from    assigned a1
left join    
        assigned a2
on      a1.id_project = a2.id_project
left join
        project p
on      a1.id_project = p.id
join    user u
on      u.id = a2.id_user
        or u.id = p.id_user
where   a1.id_user = 1

Since both subqueries have a condition where assigned.id_user = 1, I start with that query. 由于两个子查询都有一个条件,其中named.id_user = 1,因此我从该查询开始。 Let's call that assignment(s) the 'leading assignment'. 让我们将该作业称为“主要作业”。

Then join the rest, using left joins for the 'optional' tables. 然后使用“可选”表的左联接来联接其余的联接。 Use an inner join on user that matches either users of assignments linked to the leading assignment or users of projects linked to the leading project. user上使用内部联接,该内部联接与链接到主要任务的任务用户或链接到主要项目的项目user匹配。

I use distinct, because I assumen you'd want each user once, event if they have an assignment and a project (or multiple projects). 我使用“与众不同”,因为我假设您希望每个用户一次,如果他们有一个任务和一个项目(或多个项目),则为事件。

select distinct
  u.id, u.first_name, u.last_name, u.description, u.email 
from 
  assigned a
  left join assigned ap on ap.id_project = a.id_project
  left join projects p on p.id = a.id_project
  inner join users u on u.id = ap.id_user or u.id = p.id_user
where
  a.id_user = 1

Here's an alternative way to get rid of the repetition: 这是摆脱重复的另一种方法:

SELECT
  users.id,
  users.first_name,
  users.last_name,
  users.description,
  users.email 
FROM users
WHERE id IN (
  SELECT up.id_user
  FROM (
    SELECT id_user, id_project FROM assigned
    UNION ALL
    SELECT id_user, id         FROM projects
  ) up
  INNER JOIN assigned a
    ON a.id_project = up.id_project
  WHERE a.id_user = 1
)
;

That is, the assigned table's pairs of id_user, id_project are UNIONed with those of projects . 也就是说, assigned表的双id_user, id_project被合并与那些projects The resulting set is then joined with the user_id = 1 projects to obtain the list of all users who share the projects with the ID 1 user. 然后将结果集与user_id = 1项目结合在一起,以获得与ID 1用户共享项目的所有用户的列表。 And now it only remains to retrieve the details for those users, which in this case is done in the same way as in your query, ie using an IN clause. 现在只剩下检索这些用户的详细信息了,在这种情况下,这与查询中的方法相同,即使用IN子句。

I'm sorry to say that I don't have MySQL to thoroughly test the performance of this query and so cannot be quite sure if it is in any way better or worse than your original query or than the one suggested both by @GolezTrol and by @Andomar . 很遗憾地说,我没有MySQL可以全面测试该查询的性能,因此不能完全确定它是否比您的原始查询好,或者比@GolezTrol通过@Andomar Generally I tend to agree with @GolezTrol's comment that a query with simple (semi- or whatever-) joins and repetitive parts might turn out more efficient than an equivalent sophisticated query that doesn't have repetitions. 通常,我倾向于同意@GolezTrol的评论 ,即具有简单(半或任意)连接和重复部分的查询可能比没有重复的等效复杂查询更有效。 In the end, however, it is testing that must reveal the final answer for you. 然而,最后,测试必须为您揭示最终答案。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM