Hi Ken, sorry for the delay. Yes slow logging is enabled, but… it’s not picking these up. Not sure what’s going on there, But I’ve grabbed the queries from show full processlist:
SELECT COUNT(DISTINCT main.id) FROM Tickets main LEFT JOIN Groups Groups_1 ON ( Groups_1.Domain = 'RT::Ticket-Role' ) AND ( Groups_1.Instance = main.id ) LEFT JOIN CachedGroupMembers CachedGroupMembers_2 ON ( CachedGroupMembers_2.Disabled = '0' ) AND ( CachedGroupMembers_2.MemberId IN ('1567059', '498436') ) AND ( CachedGroupMembers_2.GroupId = Groups_1.id ) WHERE ( ( main.Queue IN ('3', '111') OR ( main.Owner = '1567059' AND main.Queue IN ('2') ) OR ( CachedGroupMembers_2.MemberId IS NOT NULL AND Groups_1.Name = 'Requestor' ) OR ( CachedGroupMembers_2.MemberId IS NOT NULL AND Groups_1.Name = 'AdminCc' AND main.Queue IN ('2') ) ) ) AND (main.IsMerged IS NULL) AND (main.Status != 'deleted') AND (main.Type = 'ticket') AND (main.Owner = '10' AND main.Status IN ('new', 'open'))
explain SELECT COUNT(DISTINCT main.id) FROM Tickets main LEFT JOIN Groups Groups_2 ON ( Groups_2.Domain = 'RT::Ticket-Role' ) AND ( Groups_2.Instance = main.id ) JOIN Queues Queues_1 ON ( Queues_1.id = main.Queue ) LEFT JOIN CachedGroupMembers CachedGroupMembers_3 ON ( CachedGroupMembers_3.Disabled = '0' ) AND ( CachedGroupMembers_3.MemberId IN ('1567059', '498436') ) AND ( CachedGroupMembers_3.GroupId = Groups_2.id ) WHERE ( ( main.Queue IN ('3', '111') OR ( CachedGroupMembers_3.MemberId IS NOT NULL AND Groups_2.Name = 'AdminCc' AND main.Queue IN ('2') ) OR ( main.Owner = '1567059' AND main.Queue IN ('2') ) OR ( CachedGroupMembers_3.MemberId IS NOT NULL AND Groups_2.Name = 'Requestor' ) ) ) AND (main.IsMerged IS NULL) AND (main.Status != 'deleted') AND (main.Type = 'ticket') AND (main.Queue = '111' AND ( ( Queues_1.Lifecycle = 'approvals' AND main.Status IN ('new', 'open', 'stalled') ) OR ( Queues_1.Lifecycle = 'default' AND main.Status IN ('crp', 'new', 'open', 'review', 'stalled') ) ) )
SELECT DISTINCT main.* FROM Tickets main LEFT JOIN Groups Groups_2 ON ( Groups_2.Domain = 'RT::Ticket-Role' ) AND ( Groups_2.Instance = main.id ) JOIN Queues Queues_1 ON ( Queues_1.id = main.Queue ) LEFT JOIN CachedGroupMembers CachedGroupMembers_3 ON ( CachedGroupMembers_3.Disabled = '0' ) AND ( CachedGroupMembers_3.MemberId IN ('1567059', '498436') ) AND ( CachedGroupMembers_3.GroupId = Groups_2.id ) WHERE ( ( main.Queue IN ('3', '111') OR ( CachedGroupMembers_3.MemberId IS NOT NULL AND Groups_2.Name = 'AdminCc' AND main.Queue IN ('2') ) OR ( main.Owner = '1567059' AND main.Queue IN ('2') ) OR ( CachedGroupMembers_3.MemberId IS NOT NULL AND Groups_2.Name = 'Requestor' ) ) ) AND (main.IsMerged IS NULL) AND (main.Status != 'deleted') AND (main.Type = 'ticket') AND (main.Queue = '111' AND ( ( Queues_1.Lifecycle = 'default' AND main.Status IN ('crp', 'new', 'open', 'review', 'stalled') ) OR ( Queues_1.Lifecycle = 'approvals' AND main.Status IN ('new', 'open', 'stalled') ) ) ) ORDER BY main.id ASC LIMIT 50
SELECT COUNT(DISTINCT main.id) FROM Tickets main LEFT JOIN Groups Groups_1 ON ( Groups_1.Domain = 'RT::Ticket-Role' ) AND ( Groups_1.Instance = main.id ) LEFT JOIN CachedGroupMembers CachedGroupMembers_2 ON ( CachedGroupMembers_2.Disabled = '0' ) AND ( CachedGroupMembers_2.MemberId IN ('1567059', '498436') ) AND ( CachedGroupMembers_2.GroupId = Groups_1.id ) WHERE ( ( main.Queue IN ('3', '111') OR ( main.Owner = '1567059' AND main.Queue IN ('2') ) OR ( CachedGroupMembers_2.MemberId IS NOT NULL AND Groups_1.Name = 'Requestor' ) OR ( CachedGroupMembers_2.MemberId IS NOT NULL AND Groups_1.Name = 'AdminCc' AND main.Queue IN ('2') ) ) ) AND (main.IsMerged IS NULL) AND (main.Status != 'deleted') AND (main.Type = 'ticket') AND (main.Owner = '10' AND main.Status IN ('new', 'open'));
These result in 2x query execution plans:
First:
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE main range Tickets1,Tickets2,Status,Type Tickets1 263 NULL 248 Using index condition; Using where
1 SIMPLE Queues_1 eq_ref PRIMARY PRIMARY 4 rtfet.main.Queue 1 Using where
1 SIMPLE Groups_2 ref groups1,groups2,groups3,Domain groups1 259 const 609467 Using where
1 SIMPLE CachedGroupMembers_3 ref DisGrouMem,CachedGroupMembers3,cachedgroupmembers1,SHREDDER_CGM1 DisGrouMem 5 rtfet.Groups_2.id 1 Using where; Using index
second:
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE main range Tickets1,Tickets2,Status,Type Type 67 NULL 145945 Using where; Using temporary
1 SIMPLE Queues_1 eq_ref PRIMARY PRIMARY 4 rtfet.main.Queue 1 Using where; Distinct
1 SIMPLE Groups_2 ref groups1,groups2,groups3,Domain groups1 259 const 609467 Using where; Distinct
1 SIMPLE CachedGroupMembers_3 ref DisGrouMem,CachedGroupMembers3,cachedgroupmembers1,SHREDDER_CGM1 DisGrouMem 5 rtfet.Groups_2.id 1 Using where; Using index; Distinct
One problem I can see is the queries being generated are structured inefficiently. You can rewrite the query to parse the same criteria… the simplest fix is changing the “LEFT JOIN Groups Groups_2 …” to “JOIN Groups Groups_2 …” . It’s way faster… backed up by the explain:
---------------------+--------+--------------------------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+------+-------------+----------------------+--------+------------------------------------------------------------------+------------+---------+-------------------------+--------+--------------------------------------------------------+
| 1 | SIMPLE | Groups_2 | ref | groups1,groups2,groups3,Name,Domain | groups1 | 259 | const | 607330 | Using index condition; Using temporary; Using filesort |
| 1 | SIMPLE | main | eq_ref | PRIMARY,Tickets1,Tickets2,Status,Type | PRIMARY | 4 | rtfet.Groups_2.Instance | 1 | Using where |
| 1 | SIMPLE | Queues_1 | eq_ref | PRIMARY | PRIMARY | 4 | rtfet.main.Queue | 1 | Using where; Distinct |
| 1 | SIMPLE | CachedGroupMembers_3 | ref | DisGrouMem,CachedGroupMembers3,cachedgroupmembers1,SHREDDER_CGM1 | DisGrouMem | 5 | rtfet.Groups_2.id | 1 | Using where; Using index; Distinct |
+------+-------------+----------------------+--------+------------------------------------------------------------------+------------+---------+-------------------------+--------+--------------------------------------------------------+
and you get the same benefits on the other generated queries. Same result set, a tiny fraction of the execution time…
Any idea why we’re using a LEFT JOIN there instead of INNER?
I don’t think tweaking mysql cache variables is going to help here, because the resulting record sets from multiple left joins is going to be too big.
Thanks,
Chris