2012-09-23 207 views
1

我有一個支持售票系統。我正在添加「部門」部分,用戶可以是多個部門的成員。MySQL緩慢子查詢

問題是我正在使用子查詢獲取具有位於該用戶的部門訪問表中的department_id的票證。

這是子查詢:

t.department_id IN (SELECT utd.department_id FROM users_to_departments utd WHERE utd.user_id = :department_or_assigned_or_user_id AND utd.site_id = :site_id) 

這是拖慢查詢。大約需要2秒鐘才能買到11萬張門票。子查詢是原因。

我試圖將它轉換爲左連接,然後使用HAVING utd.id不爲NULL,但速度更糟。

我想知道是否可以將它轉換爲內部連接。

問題是我總是希望獲得該用戶創建的票證,即使票證現在位於不同的部門中。

目前使用下面的子查詢TODO此之後:

OR (t.assigned_user_id = :department_or_assigned_or_user_id OR t.user_id = :department_or_assigned_or_user_id) 

所有正確的列索引,所以MySQL是沒有做任何filesorts等

的users_to_departments表只是USER_ID和部門標識。

任何幫助都會很棒。

這是我的完整查詢。

SELECT 
t.* , 
u.pushover_key AS `owner_pushover_key`, 
u.name AS `owner_name`, 
u.id AS `owner_id`, 
u.email AS `owner_email`, 
u.phone_number AS `owner_phone`, 
u.email_notifications AS `owner_email_notifications`, 
u2.pushover_key AS `assigned_pushover_key`, 
u2.name AS `assigned_name`, 
u2.id AS `assigned_id`, 
u2.email AS `assigned_email`, 
u2.email_notifications AS `assigned_email_notifications`, 
u3.name AS `submitted_name`, 
u3.id AS `submitted_id`, 
u3.email AS `submitted_email`, 
u3.email_notifications AS `submitted_email_notifications`, 
tp.name AS `priority_name`, 
td.name AS `department_name`, 
ts.name AS `status_name`, 
ts.colour AS `status_colour`, 
ts.active AS `active`, 
pa.name AS `pop_account_name` 
FROM 
tickets t 
LEFT JOIN users u ON u.id = t.user_id 
LEFT JOIN users u2 ON u2.id = t.assigned_user_id 
LEFT JOIN users u3 ON u3.id = t.submitted_user_id 
LEFT JOIN ticket_priorities tp ON tp.id = t.priority_id 
LEFT JOIN ticket_departments td ON td.id = t.department_id 
LEFT JOIN ticket_status ts ON ts.id = t.state_id 
LEFT JOIN pop_accounts pa ON pa.id = t.pop_account_id 
WHERE 
1 = 1 
AND t.site_id = :site_id 
AND ( 
    t.department_id IN (SELECT utd.department_id FROM users_to_departments utd WHERE utd.user_id = :department_or_assigned_or_user_id AND utd.site_id = :site_id) 
OR 
    (t.assigned_user_id = :department_or_assigned_or_user_id OR t.user_id = :department_or_assigned_or_user_id) 
) 
ORDER BY 
t.last_modified DESC 
LIMIT :limit OFFSET :offset 

下面是MySQL的解釋結果中的鏈接: http://michaeldale.com.au/images/explain.html

+0

什麼是mysql命令的輸出:'EXPLAIN your_query_here'? – Jocelyn

+0

感謝您的回覆。我已將帖子底部的鏈接添加到解釋結果中。 –

回答

0

enter code here如果你這麼確定你緩慢是由於被稱爲子查詢,好像你的表users_to_departments應該根據索引user_id + site_id字段。

此外,用LEFT JOIN替換IN/NOT IN或EXISTS/NOT EXIS結合NULL或NOT NULL(在WHERE子句上)對連接表的約束的確會提高SQL Server引擎的性能。

好吧考慮到我沒有充分認識到對錶中的內容,我將只爲您介紹兩個建議(我只能使用選項2或結合兩者):

1 - 我會分裂當前查詢到兩個查詢使用條款UNION ALL(平時我還使用條款ALL作出任何重複可見的,因爲它們往往代表着壞設計查詢或inadeqaute數據庫設計)

2將它們合併成一個單一的結果集 - 我嘗試替換子查詢中的IN左加入爲了評估性能增益是否符合您的需要。請注意,由於子查詢可能包含[部門 _id]上的重複項,因此您可能需要或不要在選擇之上使用DISTINCT子句。

SELECT 
DISTINCT 
t.* , 
u.pushover_key AS `owner_pushover_key`, 
u.name AS `owner_name`, 
u.id AS `owner_id`, 
u.email AS `owner_email`, 
u.phone_number AS `owner_phone`, 
u.email_notifications AS `owner_email_notifications`, 
u2.pushover_key AS `assigned_pushover_key`, 
u2.name AS `assigned_name`, 
u2.id AS `assigned_id`, 
u2.email AS `assigned_email`, 
u2.email_notifications AS `assigned_email_notifications`, 
u3.name AS `submitted_name`, 
u3.id AS `submitted_id`, 
u3.email AS `submitted_email`, 
u3.email_notifications AS `submitted_email_notifications`, 
tp.name AS `priority_name`, 
td.name AS `department_name`, 
ts.name AS `status_name`, 
ts.colour AS `status_colour`, 
ts.active AS `active`, 
pa.name AS `pop_account_name` 
FROM 
tickets t 
LEFT JOIN users u ON u.id = t.user_id 
LEFT JOIN users u2 ON u2.id = t.assigned_user_id 
LEFT JOIN users u3 ON u3.id = t.submitted_user_id 
LEFT JOIN ticket_priorities tp ON tp.id = t.priority_id 
LEFT JOIN ticket_departments td ON td.id = t.department_id 
LEFT JOIN ticket_status ts ON ts.id = t.state_id 
LEFT JOIN pop_accounts pa ON pa.id = t.pop_account_id 
LEFT JOIN users_to_departments utd ON utd.department_id = t.department_id AND utd.user_id = :department_or_assigned_or_user_id AND utd.site_id = :site_id 
WHERE  
1 = 1 
AND t.site_id = :site_id 
AND (
    utd.department_id NOT NULL 
OR 
    (t.assigned_user_id = :department_or_assigned_or_user_id OR t.user_id = :department_or_assigned_or_user_id) 
) 
ORDER BY 
t.last_modified DESC 
LIMIT :limit OFFSET :offset 

希望它可以幫助

+0

感謝您的回覆。 users_to_departments確實具有所有正確的索引。問題是子查詢是一個依賴子查詢。 是的,我認爲一個聯接會更好,只是不知道如何得到我想要的結果。 –

+0

感謝您的更新。對不起,我錯過了。看起來不錯,我會給它一個測試。 –

+0

好,所以選項2是最容易測試,似乎沒有更快。我懷疑聯盟會是一條路。 –