[rt-devel] postgres query optimising (was: Re: [rt-users] Is this slow? It seems slow.)
Jamie Wilkinson
jaq at spacepants.org
Thu Jun 12 01:28:51 EDT 2003
This one time, at band camp, Jesse Vincent wrote:
>RT runs on Mysql 3, whichi doesn't support UNION, which is one reason
>I'm leery of switching to something that requires a UNION in the middle
>of a stable series.
I've got two queries now, derived from the one that is being generated, that
returns what looks to be the same results from the database. Unfortunately
I'm coming at a few brick walls trying to implement either of them in
WhoHasRight.
So, attached are the two queries. The first uses a union, the second
removes the joins.
My gut feeling is that the query as being constructed *isn't* totally
correct -- the duplicated aliases and joins seem to be confusing the
problem. Each half of the WhichGroup OR check_roles block (see the code to
WhoHaveRight for the naming) isnt' actually related to each other, but
because they're both using the same aliases compounded with the 4 way join,
Postgres is treating it like either half depends on the contents of the
other, and so it's slow. When the OR is broken up explicitly with the
UNION, or by removing the JOINs, Postgres can make some better decisions
about the query. (disclaimer: I am only guessing here, may be talking out
of my arse -- but the observations seem to hold)
The union select runs much faster than the no-JOIN query, so I'd prefer the
final implementation to use that one. As for mysql support, the union
select could be implemented in DBIx::Searchbuilder simply by running the two
queries and concatenating the results in perl code.
So, the way forward looks like supporting UNION in SearchBuilder, and then
using that functionality in RT.
--
jaq at spacepants.org http://spacepants.org/jaq.gpg
-------------- next part --------------
explain analyze
SELECt dISTINCT main.* FROM
(
(
(
(
Users main
JOIN Principals as Principals_1 ON (main.id = Principals_1.id)
)
JOIN CachedGroupMembers as CachedGroupMembers_5 ON (Principals_1.id = CachedGroupMembers_5.MemberId)
)
JOIN CachedGroupMembers as CachedGroupMembers_6 ON (Principals_1.id = CachedGroupMembers_6.MemberId)
)
JOIN Principals as Principals_3 ON (CachedGroupMembers_5.GroupId = Principals_3.id)
),
Groups Groups_2,
ACL ACL_4
WHERE
(
(ACL_4.RightName = 'SuperUser')
OR
(ACL_4.RightName = 'OwnTicket')
)
AND
(
(CachedGroupMembers_6.GroupId = '4')
)
AND
(
(Principals_1.Disabled = '0')
)
AND
(
(Principals_1.PrincipalType = 'User')
)
AND
(
ACL_4.ObjectType = 'RT::System'
OR
(
ACL_4.ObjectType = 'RT::Queue'
AND
ACL_4.ObjectId = 5
)
)
AND
(
ACL_4.PrincipalId = Principals_3.id
AND
Principals_3.id = Groups_2.id
AND
ACL_4.PrincipalType = 'Group'
AND
(
Groups_2.Domain = 'SystemInternal'
OR
Groups_2.Domain = 'UserDefined'
OR
Groups_2.Domain = 'ACLEquivalence'
)
)
)
AND
Principals_1.id = main.id
union
SELECT DISTINCT main.* FROM
(
(
(
(
Users main
JOIN Principals as Principals_1 ON (main.id = Principals_1.id)
)
JOIN CachedGroupMembers as CachedGroupMembers_5 ON (Principals_1.id = CachedGroupMembers_5.MemberId)
)
JOIN CachedGroupMembers as CachedGroupMembers_6 ON (Principals_1.id = CachedGroupMembers_6.MemberId)
)
JOIN Principals as Principals_3 ON (CachedGroupMembers_5.GroupId = Principals_3.id)
),
Groups Groups_2,
ACL ACL_4
WHERE
(
(ACL_4.RightName = 'SuperUser')
OR
(ACL_4.RightName = 'OwnTicket')
)
AND
(
(CachedGroupMembers_6.GroupId = '4')
)
AND (
(Principals_1.Disabled = '0')
) AND
(
(Principals_1.PrincipalType = 'User') )
AND
(
ACL_4.ObjectType = 'RT::System'
OR
(
ACL_4.ObjectType = 'RT::Queue'
AND
ACL_4.ObjectId = 5
)
)
AND
(
(
(
Groups_2.Domain = 'RT::Queue-Role'
AND
Groups_2.Instance = 5
)
OR
(
Groups_2.Domain = 'RT::Ticket-Role'
AND
Groups_2.Instance = 388
)
)
AND
Groups_2.Type = ACL_4.PrincipalType
AND
Groups_2.id = Principals_3.id
AND
Principals_3.PrincipalType = 'Group'
)
AND
Principals_1.id = main.id
;
-------------- next part --------------
select distinct users.* from
users,
groups,
principals,
acl,
cachedgroupmembers
where
cachedgroupmembers.groupid = 4
and
cachedgroupmembers.memberid = principals.id
and
acl.rightname in ('SuperUser', 'OwnTicket')
and
principals.disabled = 0
and
principals.principaltype = 'User'
and
(
acl.objecttype = 'RT::System'
or
(acl.objecttype = 'RT::Queue'
and
acl.objectid = 4
)
)
and
principals.id = users.id
and
(
(
(groups.domain = 'RT::Ticket-Role' and groups.instance = 388)
or
(groups.domain = 'RT::Queue-Role' and groups.instance = 5)
and
groups.type = acl.principaltype
and
groups.id = principals.id
and
principals.principaltype = 'Group'
)
or
(
acl.principalid = principals.id
and
principals.id = groups.id
and
acl.principaltype = 'Group'
and
groups.domain in ('SystemInternal', 'UserDefined', 'ACLEquivalence')
)
)
;
More information about the Rt-devel
mailing list