2017-10-20 236 views
1

以下查询需要30多秒才能运行。根据我运行的类似查询,我看不到这里的阻挡位置。我唯一的想法是将作业用户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 
+0

你的桌子有多大?他们如何索引? –

+2

你也可以发布查询的解释。 (只需在选择前面输入“EXPLAIN”并运行查询) –

+0

是'user_id'所有这些表中的主键?如果不是,它被索引? – alfasin

回答

5

使用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)
+0

看到您的答案后,我现在明白了为什么原始查询使用外部联接 - 它需要处理仅与其他表中的一个匹配的ID。 – Barmar

+0

没有更新索引,这个更新的查询削减20秒(8 vs 28)。谢谢!一旦更新索引到位,将会对速度发表评论。 – Klav

+0

对于'job_applicants',我会使用索引'(user_id,process_level,job_id)',因为在您使用'job_id'连接下一个表之前,您首先需要通过'process_level'进行过滤。 –

1

这SH会工作。它在概念上与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 
2

又一种方法。这有第一收集的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秒。

+0

确实如此。这很快! – Klav