1

我有一个支持票务系统。我正在添加部门部分,其中用户可以是多个部门的成员。

问题是我正在使用子查询来获取具有该用户的部门访问表中的部门 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)

这会减慢查询速度。一张包含 110,000 张票的表格大约需要 2 秒。子查询是原因。

我尝试将其转换为 LEFT JOIN,然后使用 HAVING utd.id IS NOT NULL,但速度更差。

我想知道是否可以将其转换为内部联接。

问题是我总是想获得由该用户创建的票,即使票现在在不同的部门。

目前在子查询之后使用以下内容:

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

所有正确的列都被索引,所以 MySQL 不做任何文件排序等。

users_to_departments 表只是 user_id 和 department_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

4

1 回答 1

0

enter code here如果您非常确定您的缓慢是由于引用的子查询,那么您的表users_to_departments似乎应该有一个基于user_id + site_id字段的索引。

此外,将 IN/NOT IN 或 EXISTS/NOT EXISTS 替换为 LEFT JOIN 并结合 NULL 或 NOT NULL(在 WHERE 子句上)对连接表的约束确实提高了 SQL Server 引擎的性能。

好吧,考虑到我对表格内容并不完全了解,我只会向您提出两个建议(我您只能使用选项 2 或将两者结合使用):

1 - 我会将当前查询拆分为两个查询,并使用子句UNION ALL将它们连接到一个结果集中(通常我也使用子句ALL使任何重复项可见,因为它们通常代表设计不良的查询或数据库设计不足)

2 - 我会尝试用LEFT JOIN替换IN子查询,以评估性能提升是否符合您的需要。请注意,由于子查询可能在 [ department_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 

希望能帮助到你

于 2012-09-23T01:13:33.403 回答