2012-09-23 170 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是最容易测试,似乎没有更快。我怀疑联盟会是一条路。 –