简体   繁体   中英

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. 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:

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.

You could start with the project assignments of user 1 a1 . Then find all assignments of other people to those projects a2 , and the user in the project table p . The users you are looking for are then in either a2 or p . I added distinct to remove users who can be reached in both ways.

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. 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.

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 . 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. 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.

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 . 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. In the end, however, it is testing that must reveal the final answer for you.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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