2017-10-20 233 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