极慢的查询

Extremely slow query

下面是一个需要 30 多秒才能到达 运行 的查询。基于我有 运行ning 的类似查询,我看不出问题在哪里。我唯一的想法是将作业用户 ID 加入 job_applicants 用户 ID,但它们需要映射。

SELECT DISTINCT u.user_id, u.first_name, u.last_name FROM users u
LEFT OUTER JOIN employee_access ea ON ea.user_id = u.user_id
LEFT OUTER JOIN confirmation c ON c.user_id = u.user_id
LEFT OUTER JOIN job_applicants a ON a.user_id = u.user_id
LEFT OUTER JOIN job j ON j.job_id = a.job_id
WHERE ea.access_id = 4 OR c.access_id = 4 OR (a.process_level = 0 AND j.access_id = 4) 
ORDER BY u.last_name asc

使用exists:

select u.*
from users u
where exists (select 1
              from employee_access ea 
              where ea.user_id = u.user_id and ea.access_id = 4
             ) or
      exists (select 1
              from confirmation c 
              where c.user_id = u.user_id and c.access_id = 4
             ) or
      exists (select 1
              from job_applicants a join
                   job j 
                   on j.job_id = a.job_id
              where a.user_id = u.user_id and
                    a.process_level = 0 AND j.access_id = 4
             )
order by u.last_name;

这将阻止所有笛卡尔积和最终去除重复项。

我会推荐以下索引:

  • users(last_name, user_id)
  • employee_access(user_id, access_id)
  • confirmation(user_id, access_id)
  • job_applicants(user_id, process_level, job_id)
  • job(job_id, access_id)

这应该有效。它在概念上与 Gordon 的回答相似 但我对相关子查询有一种病态的不信任

SELECT DISTINCT u.user_id, u.first_name, u.last_name 
FROM users u
WHERE u.user_id IN (SELECT user_id FROM employee_access WHERE access_id = 4)
   OR u.user_id IN (SELECT user_id FROM confirmation WHERE access_id = 4)
   OR u.user_id IN (
        SELECT a.user_id 
        FROM job_applicants a 
        INNER JOIN job j ON j.job_id = a.job_id
        WHERE a.process_level = 0 AND j.access_id = 4
      )
ORDER BY u.last_name asc

另一种方法。这具有 首先 收集 user_ids 列表的优势, 然后 进入 users 其他列:

SELECT  u.user_id, u.first_name, u.last_name
    FROM  users u
    JOIN (
        ( SELECT user_id FROM employee_access WHERE access_id = 4 )
        UNION DISTINCT
        ( SELECT user_id FROM confirmation    WHERE access_id = 4 )
        UNION DISTINCT
        ( SELECT a.user_id 
              FROM job_applicants a 
              JOIN job j  USING(job_id)
              WHERE a.process_level = 0
                AND j.access_id = 4 )
    ) AS x USING(user_id)
    ORDER BY u.last_name ASC

索引:

employee_access: INDEX(access_id, user_id)  -- (covering)
confirmation:    INDEX(access_id, user_id)  -- (covering)
job:             INDEX(access_id, job_id)  -- (covering)
job_applicants:  INDEX(process_level, job_id, user_id)  -- (covering)
users:  PRIMARY KEY(user_id)

看看这是否会缩短剩余 8 秒的大部分时间。