1

サポートチケットシステムがあります。現在、ユーザーが複数の部門のメンバーになることができる部門セクションを追加しています。

問題は、サブクエリを使用して、そのユーザーの部門アクセステーブルにある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)

これにより、クエリの速度が低下します。11万枚のチケットのテーブルには約2秒かかります。サブクエリが原因です。

それをLEFTJOINに変換してから、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 Explainの結果へのリンクは次のとおりです:http: //michaeldale.com.au/images/explain.html

4

1 に答える 1

0

enter code here参照されたサブクエリが原因で速度が低下していることが確実な場合は、テーブルusers_to_departmentsにuser_id + site_idフィールドに基づくインデックスが必要であると思われます。

さらに、結合テーブルのIN /NOTINまたはEXISTS/NOTEXISTSをNULLまたはNOTNULL(WHERE句)制約と組み合わせたLEFT JOINに置き換えると、SQLServerエンジンのパフォーマンスが実際に向上します。

私はテーブルの内容を十分に認識していないことを十分に考慮して、2つの提案を提示します(オプション2のみを使用するか、両方を組み合わせることができます)。

1-現在のクエリを2つのクエリに分割し、UNION ALL句を使用してそれらを単一の結果セットに結合します(通常、ALL句を使用して重複を表示します。これは、多くの場合、不適切な設計のクエリまたは不適切なデータベース設計を表すためです)。

2-パフォーマンスの向上がニーズに合っているかどうかを評価するために、 INサブクエリをLEFTJOINに置き換えようとします。サブクエリには[ 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 に答える