Thread: Help with optimizing a sql statement

Help with optimizing a sql statement

From
Rafael Martinez Guerrero
Date:
Hello

We are running an application via web that use a lot of time to perform
some operations. We are trying to find out if some of the sql statements
used are the reason of the slow speed.

We have identified a sql that takes like 4-5000ms more than the second
slowest sql in out test server. I hope that we will get some help to try
to optimize it.

Thanks in advance for any help.

Some information:
********************************************************************************
rttest=# EXPLAIN ANALYZE SELECT DISTINCT main.*

FROM Users main ,
     Principals Principals_1,
     ACL ACL_2,
     Groups Groups_3,
     CachedGroupMembers CachedGroupMembers_4

WHERE ((ACL_2.RightName = 'OwnTicket'))
AND ((CachedGroupMembers_4.MemberId = Principals_1.id))
AND ((Groups_3.id = CachedGroupMembers_4.GroupId))
AND ((Principals_1.Disabled = '0') or (Principals_1.Disabled = '0'))
AND ((Principals_1.id != '1'))
AND ((main.id = Principals_1.id))
AND  ( (    ACL_2.PrincipalId = Groups_3.id AND ACL_2.PrincipalType =
'Group' AND (   Groups_3.Domain = 'SystemInternal' OR Groups_3.Domain =
'UserDefined' OR Groups_3.Domain = 'ACLEquivalence')) OR ( (
(Groups_3.Domain = 'RT::Queue-Role' ) )  AND Groups_3.Type
=ACL_2.PrincipalType) )
AND (ACL_2.ObjectType = 'RT::System' OR (ACL_2.ObjectType = 'RT::Queue')
)

ORDER BY main.Name ASC

QUERY PLAN
-----------------------------------------------------------------
 Unique  (cost=28394.99..28395.16 rows=2 width=706) (actual
time=15574.272..15787.681 rows=254 loops=1)
   ->  Sort  (cost=28394.99..28394.99 rows=2 width=706) (actual
time=15574.267..15607.310 rows=22739 loops=1)
         Sort Key: main.name, main.id, main."password", main.comments,
main.signature, main.emailaddress, main.freeformcontactinfo,
main.organization, main.realname, main.nickname, main.lang,
main.emailencoding, main.webencoding, main.externalcontactinfoid,
main.contactinfosystem, main.externalauthid, main.authsystem,
main.gecos, main.homephone, main.workphone, main.mobilephone,
main.pagerphone, main.address1, main.address2, main.city, main.state,
main.zip, main.country, main.timezone, main.pgpkey, main.creator,
main.created, main.lastupdatedby, main.lastupdated
         ->  Nested Loop  (cost=20825.91..28394.98 rows=2 width=706)
(actual time=1882.608..14589.596 rows=22739 loops=1)
               Join Filter: (((("inner"."domain")::text =
'RT::Queue-Role'::text) OR ("outer".principalid = "inner".id)) AND
((("inner"."type")::text = ("outer".principaltype)::text) OR
("outer".principalid = "inner".id)) AND ((("inner"."domain")::text =
'RT::Queue-Role'::text) OR (("outer".principaltype)::text =
'Group'::text)) AND ((("inner"."type")::text =
("outer".principaltype)::text) OR (("outer".principaltype)::text =
'Group'::text)) AND ((("inner"."type")::text =
("outer".principaltype)::text) OR (("inner"."domain")::text =
'SystemInternal'::text) OR (("inner"."domain")::text =
'UserDefined'::text) OR (("inner"."domain")::text =
'ACLEquivalence'::text)))
               ->  Seq Scan on acl acl_2  (cost=0.00..40.57 rows=45
width=13) (actual time=0.020..1.730 rows=51 loops=1)
                     Filter: (((rightname)::text = 'OwnTicket'::text)
AND (((objecttype)::text = 'RT::System'::text) OR ((objecttype)::text =
'RT::Queue'::text)))
               ->  Materialize  (cost=20825.91..20859.37 rows=3346
width=738) (actual time=36.925..166.374 rows=66823 loops=51)
                     ->  Merge Join  (cost=15259.56..20825.91 rows=3346
width=738) (actual time=1882.539..3538.258 rows=66823 loops=1)
                           Merge Cond: ("outer".id = "inner".memberid)
                           ->  Merge Join  (cost=0.00..5320.37
rows=13182 width=710) (actual time=0.116..874.960 rows=13167 loops=1)
                                 Merge Cond: ("outer".id = "inner".id)
                                 ->  Index Scan using users_pkey on
users main  (cost=0.00..1063.60 rows=13181 width=706) (actual
time=0.032..52.355 rows=13181 loops=1)
                                 ->  Index Scan using principals_pkey on
principals principals_1  (cost=0.00..3737.49 rows=141801 width=4)
(actual time=0.020..463.043 rows=141778 loops=1)
                                       Filter: ((disabled = 0::smallint)
AND (id <> 1))
                           ->  Sort  (cost=15259.56..15349.54 rows=35994
width=36) (actual time=1882.343..1988.353 rows=80357 loops=1)
                                 Sort Key: cachedgroupmembers_4.memberid
                                 ->  Hash Join  (cost=3568.51..12535.63
rows=35994 width=36) (actual time=96.151..1401.537 rows=80357 loops=1)
                                       Hash Cond: ("outer".groupid =
"inner".id)
                                       ->  Seq Scan on
cachedgroupmembers cachedgroupmembers_4  (cost=0.00..5961.53 rows=352753
width=8) (actual time=0.011..500.508 rows=352753 loops=1)
                                       ->  Hash  (cost=3535.70..3535.70
rows=13124 width=32) (actual time=95.966..95.966 rows=0 loops=1)
                                             ->  Index Scan using
groups1, groups1, groups1, groups1 on groups groups_3
(cost=0.00..3535.70 rows=13124 width=32) (actual time=0.045..76.506
rows=13440 loops=1)
                                                   Index Cond:
((("domain")::text = 'RT::Queue-Role'::text) OR (("domain")::text =
'SystemInternal'::text) OR (("domain")::text = 'UserDefined'::text) OR
(("domain")::text = 'ACLEquivalence'::text))

 Total runtime: 15825.022 ms

********************************************************************************
rttest=# \d users
                                        Table "public.users"
        Column         |            Type             |
Modifiers
-----------------------+-----------------------------+------------------------------------------------
 id                    | integer                     | not null default
nextval('users_id_seq'::text)
 name                  | character varying(200)      | not null
 password              | character varying(40)       |
 comments              | text                        |
 signature             | text                        |
 emailaddress          | character varying(120)      |
 freeformcontactinfo   | text                        |
 organization          | character varying(200)      |
 realname              | character varying(120)      |
 nickname              | character varying(16)       |
 lang                  | character varying(16)       |
 emailencoding         | character varying(16)       |
 webencoding           | character varying(16)       |
 externalcontactinfoid | character varying(100)      |
 contactinfosystem     | character varying(30)       |
 externalauthid        | character varying(100)      |
 authsystem            | character varying(30)       |
 gecos                 | character varying(16)       |
 homephone             | character varying(30)       |
 workphone             | character varying(30)       |
 mobilephone           | character varying(30)       |
 pagerphone            | character varying(30)       |
 address1              | character varying(200)      |
 address2              | character varying(200)      |
 city                  | character varying(100)      |
 state                 | character varying(100)      |
 zip                   | character varying(16)       |
 country               | character varying(50)       |
 timezone              | character varying(50)       |
 pgpkey                | text                        |
 creator               | integer                     | not null default
0
 created               | timestamp without time zone |
 lastupdatedby         | integer                     | not null default
0
 lastupdated           | timestamp without time zone |
Indexes:
    "users_pkey" primary key, btree (id)
    "users1" unique, btree (name)
    "users2" btree (name)
    "users3" btree (id, emailaddress)
    "users4" btree (emailaddress)
********************************************************************************
rttest=# \d principals

                                  Table "public.principals"
    Column     |         Type          |
Modifiers
---------------+-----------------------+----------------------------------------
 id            | integer               | not null default
nextval('principals_id_seq'::text)
 principaltype | character varying(16) | not null
 objectid      | integer               |
 disabled      | smallint              | not null default 0
Indexes:
    "principals_pkey" primary key, btree (id)
    "principals2" btree (objectid)

********************************************************************************
rttest=# \d acl

                                  Table "public.acl"
    Column     |         Type          |
Modifiers
---------------+-----------------------+----------------------------------------------
 id            | integer               | not null default
nextval('acl_id_seq'::text)
 principaltype | character varying(25) | not null
 principalid   | integer               | not null
 rightname     | character varying(25) | not null
 objecttype    | character varying(25) | not null
 objectid      | integer               | not null default 0
 delegatedby   | integer               | not null default 0
 delegatedfrom | integer               | not null default 0
Indexes:
    "acl_pkey" primary key, btree (id)
    "acl1" btree (rightname, objecttype, objectid, principaltype,
principalid)


********************************************************************************
rttest=# \d groups

                                 Table "public.groups"
   Column    |          Type          |
Modifiers
-------------+------------------------+-------------------------------------------------
 id          | integer                | not null default
nextval('groups_id_seq'::text)
 name        | character varying(200) |
 description | character varying(255) |
 domain      | character varying(64)  |
 type        | character varying(64)  |
 instance    | integer                |
Indexes:
    "groups_pkey" primary key, btree (id)
    "groups1" unique, btree ("domain", instance, "type", id, name)
    "groups2" btree ("type", instance, "domain")


********************************************************************************
 rttest=# \d  cachedgroupmembers"

                          Table "public.cachedgroupmembers"
      Column       |   Type   |
Modifiers
-------------------+----------+-------------------------------------------------------------
 id                | integer  | not null default
nextval('cachedgroupmembers_id_seq'::text)
 groupid           | integer  |
 memberid          | integer  |
 via               | integer  |
 immediateparentid | integer  |
 disabled          | smallint | not null default 0
Indexes:
    "cachedgroupmembers_pkey" primary key, btree (id)
    "cachedgroupmembers2" btree (memberid)
    "cachedgroupmembers3" btree (groupid)
    "disgroumem" btree (groupid, memberid, disabled)


********************************************************************************

--
Rafael Martinez, <r.m.guerrero@usit.uio.no>
Center for Information Technology Services
University of Oslo, Norway

PGP Public Key: http://folk.uio.no/rafael/


Re: Help with optimizing a sql statement

From
"Jim C. Nasby"
Date:
At least part of the problem is that it's way off on some of the row
estimates. I'd suggest upping the statisticss target on at least all of
the join columns to at least 100. (Note that it's doing a nested loop
thinking it will have only 2 rows but it actually has 22000 rows).

On Thu, Feb 09, 2006 at 04:10:27PM +0100, Rafael Martinez Guerrero wrote:
> Hello
>
> We are running an application via web that use a lot of time to perform
> some operations. We are trying to find out if some of the sql statements
> used are the reason of the slow speed.
>
> We have identified a sql that takes like 4-5000ms more than the second
> slowest sql in out test server. I hope that we will get some help to try
> to optimize it.
>
> Thanks in advance for any help.
>
> Some information:
> ********************************************************************************
> rttest=# EXPLAIN ANALYZE SELECT DISTINCT main.*
>
> FROM Users main ,
>      Principals Principals_1,
>      ACL ACL_2,
>      Groups Groups_3,
>      CachedGroupMembers CachedGroupMembers_4
>
> WHERE ((ACL_2.RightName = 'OwnTicket'))
> AND ((CachedGroupMembers_4.MemberId = Principals_1.id))
> AND ((Groups_3.id = CachedGroupMembers_4.GroupId))
> AND ((Principals_1.Disabled = '0') or (Principals_1.Disabled = '0'))
> AND ((Principals_1.id != '1'))
> AND ((main.id = Principals_1.id))
> AND  ( (    ACL_2.PrincipalId = Groups_3.id AND ACL_2.PrincipalType =
> 'Group' AND (   Groups_3.Domain = 'SystemInternal' OR Groups_3.Domain =
> 'UserDefined' OR Groups_3.Domain = 'ACLEquivalence')) OR ( (
> (Groups_3.Domain = 'RT::Queue-Role' ) )  AND Groups_3.Type
> =ACL_2.PrincipalType) )
> AND (ACL_2.ObjectType = 'RT::System' OR (ACL_2.ObjectType = 'RT::Queue')
> )
>
> ORDER BY main.Name ASC
>
> QUERY PLAN
> -----------------------------------------------------------------
>  Unique  (cost=28394.99..28395.16 rows=2 width=706) (actual
> time=15574.272..15787.681 rows=254 loops=1)
>    ->  Sort  (cost=28394.99..28394.99 rows=2 width=706) (actual
> time=15574.267..15607.310 rows=22739 loops=1)
>          Sort Key: main.name, main.id, main."password", main.comments,
> main.signature, main.emailaddress, main.freeformcontactinfo,
> main.organization, main.realname, main.nickname, main.lang,
> main.emailencoding, main.webencoding, main.externalcontactinfoid,
> main.contactinfosystem, main.externalauthid, main.authsystem,
> main.gecos, main.homephone, main.workphone, main.mobilephone,
> main.pagerphone, main.address1, main.address2, main.city, main.state,
> main.zip, main.country, main.timezone, main.pgpkey, main.creator,
> main.created, main.lastupdatedby, main.lastupdated
>          ->  Nested Loop  (cost=20825.91..28394.98 rows=2 width=706)
> (actual time=1882.608..14589.596 rows=22739 loops=1)
>                Join Filter: (((("inner"."domain")::text =
> 'RT::Queue-Role'::text) OR ("outer".principalid = "inner".id)) AND
> ((("inner"."type")::text = ("outer".principaltype)::text) OR
> ("outer".principalid = "inner".id)) AND ((("inner"."domain")::text =
> 'RT::Queue-Role'::text) OR (("outer".principaltype)::text =
> 'Group'::text)) AND ((("inner"."type")::text =
> ("outer".principaltype)::text) OR (("outer".principaltype)::text =
> 'Group'::text)) AND ((("inner"."type")::text =
> ("outer".principaltype)::text) OR (("inner"."domain")::text =
> 'SystemInternal'::text) OR (("inner"."domain")::text =
> 'UserDefined'::text) OR (("inner"."domain")::text =
> 'ACLEquivalence'::text)))
>                ->  Seq Scan on acl acl_2  (cost=0.00..40.57 rows=45
> width=13) (actual time=0.020..1.730 rows=51 loops=1)
>                      Filter: (((rightname)::text = 'OwnTicket'::text)
> AND (((objecttype)::text = 'RT::System'::text) OR ((objecttype)::text =
> 'RT::Queue'::text)))
>                ->  Materialize  (cost=20825.91..20859.37 rows=3346
> width=738) (actual time=36.925..166.374 rows=66823 loops=51)
>                      ->  Merge Join  (cost=15259.56..20825.91 rows=3346
> width=738) (actual time=1882.539..3538.258 rows=66823 loops=1)
>                            Merge Cond: ("outer".id = "inner".memberid)
>                            ->  Merge Join  (cost=0.00..5320.37
> rows=13182 width=710) (actual time=0.116..874.960 rows=13167 loops=1)
>                                  Merge Cond: ("outer".id = "inner".id)
>                                  ->  Index Scan using users_pkey on
> users main  (cost=0.00..1063.60 rows=13181 width=706) (actual
> time=0.032..52.355 rows=13181 loops=1)
>                                  ->  Index Scan using principals_pkey on
> principals principals_1  (cost=0.00..3737.49 rows=141801 width=4)
> (actual time=0.020..463.043 rows=141778 loops=1)
>                                        Filter: ((disabled = 0::smallint)
> AND (id <> 1))
>                            ->  Sort  (cost=15259.56..15349.54 rows=35994
> width=36) (actual time=1882.343..1988.353 rows=80357 loops=1)
>                                  Sort Key: cachedgroupmembers_4.memberid
>                                  ->  Hash Join  (cost=3568.51..12535.63
> rows=35994 width=36) (actual time=96.151..1401.537 rows=80357 loops=1)
>                                        Hash Cond: ("outer".groupid =
> "inner".id)
>                                        ->  Seq Scan on
> cachedgroupmembers cachedgroupmembers_4  (cost=0.00..5961.53 rows=352753
> width=8) (actual time=0.011..500.508 rows=352753 loops=1)
>                                        ->  Hash  (cost=3535.70..3535.70
> rows=13124 width=32) (actual time=95.966..95.966 rows=0 loops=1)
>                                              ->  Index Scan using
> groups1, groups1, groups1, groups1 on groups groups_3
> (cost=0.00..3535.70 rows=13124 width=32) (actual time=0.045..76.506
> rows=13440 loops=1)
>                                                    Index Cond:
> ((("domain")::text = 'RT::Queue-Role'::text) OR (("domain")::text =
> 'SystemInternal'::text) OR (("domain")::text = 'UserDefined'::text) OR
> (("domain")::text = 'ACLEquivalence'::text))
>
>  Total runtime: 15825.022 ms
>
> ********************************************************************************
> rttest=# \d users
>                                         Table "public.users"
>         Column         |            Type             |
> Modifiers
> -----------------------+-----------------------------+------------------------------------------------
>  id                    | integer                     | not null default
> nextval('users_id_seq'::text)
>  name                  | character varying(200)      | not null
>  password              | character varying(40)       |
>  comments              | text                        |
>  signature             | text                        |
>  emailaddress          | character varying(120)      |
>  freeformcontactinfo   | text                        |
>  organization          | character varying(200)      |
>  realname              | character varying(120)      |
>  nickname              | character varying(16)       |
>  lang                  | character varying(16)       |
>  emailencoding         | character varying(16)       |
>  webencoding           | character varying(16)       |
>  externalcontactinfoid | character varying(100)      |
>  contactinfosystem     | character varying(30)       |
>  externalauthid        | character varying(100)      |
>  authsystem            | character varying(30)       |
>  gecos                 | character varying(16)       |
>  homephone             | character varying(30)       |
>  workphone             | character varying(30)       |
>  mobilephone           | character varying(30)       |
>  pagerphone            | character varying(30)       |
>  address1              | character varying(200)      |
>  address2              | character varying(200)      |
>  city                  | character varying(100)      |
>  state                 | character varying(100)      |
>  zip                   | character varying(16)       |
>  country               | character varying(50)       |
>  timezone              | character varying(50)       |
>  pgpkey                | text                        |
>  creator               | integer                     | not null default
> 0
>  created               | timestamp without time zone |
>  lastupdatedby         | integer                     | not null default
> 0
>  lastupdated           | timestamp without time zone |
> Indexes:
>     "users_pkey" primary key, btree (id)
>     "users1" unique, btree (name)
>     "users2" btree (name)
>     "users3" btree (id, emailaddress)
>     "users4" btree (emailaddress)
> ********************************************************************************
> rttest=# \d principals
>
>                                   Table "public.principals"
>     Column     |         Type          |
> Modifiers
> ---------------+-----------------------+----------------------------------------
>  id            | integer               | not null default
> nextval('principals_id_seq'::text)
>  principaltype | character varying(16) | not null
>  objectid      | integer               |
>  disabled      | smallint              | not null default 0
> Indexes:
>     "principals_pkey" primary key, btree (id)
>     "principals2" btree (objectid)
>
> ********************************************************************************
> rttest=# \d acl
>
>                                   Table "public.acl"
>     Column     |         Type          |
> Modifiers
> ---------------+-----------------------+----------------------------------------------
>  id            | integer               | not null default
> nextval('acl_id_seq'::text)
>  principaltype | character varying(25) | not null
>  principalid   | integer               | not null
>  rightname     | character varying(25) | not null
>  objecttype    | character varying(25) | not null
>  objectid      | integer               | not null default 0
>  delegatedby   | integer               | not null default 0
>  delegatedfrom | integer               | not null default 0
> Indexes:
>     "acl_pkey" primary key, btree (id)
>     "acl1" btree (rightname, objecttype, objectid, principaltype,
> principalid)
>
>
> ********************************************************************************
> rttest=# \d groups
>
>                                  Table "public.groups"
>    Column    |          Type          |
> Modifiers
> -------------+------------------------+-------------------------------------------------
>  id          | integer                | not null default
> nextval('groups_id_seq'::text)
>  name        | character varying(200) |
>  description | character varying(255) |
>  domain      | character varying(64)  |
>  type        | character varying(64)  |
>  instance    | integer                |
> Indexes:
>     "groups_pkey" primary key, btree (id)
>     "groups1" unique, btree ("domain", instance, "type", id, name)
>     "groups2" btree ("type", instance, "domain")
>
>
> ********************************************************************************
>  rttest=# \d  cachedgroupmembers"
>
>                           Table "public.cachedgroupmembers"
>       Column       |   Type   |
> Modifiers
> -------------------+----------+-------------------------------------------------------------
>  id                | integer  | not null default
> nextval('cachedgroupmembers_id_seq'::text)
>  groupid           | integer  |
>  memberid          | integer  |
>  via               | integer  |
>  immediateparentid | integer  |
>  disabled          | smallint | not null default 0
> Indexes:
>     "cachedgroupmembers_pkey" primary key, btree (id)
>     "cachedgroupmembers2" btree (memberid)
>     "cachedgroupmembers3" btree (groupid)
>     "disgroumem" btree (groupid, memberid, disabled)
>
>
> ********************************************************************************
>
> --
> Rafael Martinez, <r.m.guerrero@usit.uio.no>
> Center for Information Technology Services
> University of Oslo, Norway
>
> PGP Public Key: http://folk.uio.no/rafael/
>
>
> ---------------------------(end of broadcast)---------------------------
> TIP 9: In versions below 8.0, the planner will ignore your desire to
>        choose an index scan if your joining column's datatypes do not
>        match
>

--
Jim C. Nasby, Sr. Engineering Consultant      jnasby@pervasive.com
Pervasive Software      http://pervasive.com    work: 512-231-6117
vcard: http://jim.nasby.net/pervasive.vcf       cell: 512-569-9461

Re: Help with optimizing a sql statement

From
"Dave Dutcher"
Date:
First I'm wondering if the tables have been recently analyzed.  If an
analyze has been run recently, then it is probably a good idea to look
at the statistics target.


-----Original Message-----
From: pgsql-performance-owner@postgresql.org
[mailto:pgsql-performance-owner@postgresql.org] On Behalf Of Jim C.
Nasby
Sent: Thursday, February 09, 2006 1:34 PM
To: Rafael Martinez Guerrero
Cc: pgsql-performance@postgresql.org
Subject: Re: [PERFORM] Help with optimizing a sql statement

At least part of the problem is that it's way off on some of the row
estimates. I'd suggest upping the statisticss target on at least all of
the join columns to at least 100. (Note that it's doing a nested loop
thinking it will have only 2 rows but it actually has 22000 rows).

On Thu, Feb 09, 2006 at 04:10:27PM +0100, Rafael Martinez Guerrero
wrote:
> Hello
>
> We are running an application via web that use a lot of time to
perform
> some operations. We are trying to find out if some of the sql
statements
> used are the reason of the slow speed.
>
> We have identified a sql that takes like 4-5000ms more than the second
> slowest sql in out test server. I hope that we will get some help to
try
> to optimize it.
>
> Thanks in advance for any help.
>
[Snip]


Re: Help with optimizing a sql statement

From
"Jim C. Nasby"
Date:
I looked at the estimates for the table access methods and they all
looked ok, so I think the statistics are pretty up-to-date; there just
aren't enough of them for the planner to do a good job.

On Thu, Feb 09, 2006 at 01:44:22PM -0600, Dave Dutcher wrote:
> First I'm wondering if the tables have been recently analyzed.  If an
> analyze has been run recently, then it is probably a good idea to look
> at the statistics target.
>
>
> -----Original Message-----
> From: pgsql-performance-owner@postgresql.org
> [mailto:pgsql-performance-owner@postgresql.org] On Behalf Of Jim C.
> Nasby
> Sent: Thursday, February 09, 2006 1:34 PM
> To: Rafael Martinez Guerrero
> Cc: pgsql-performance@postgresql.org
> Subject: Re: [PERFORM] Help with optimizing a sql statement
>
> At least part of the problem is that it's way off on some of the row
> estimates. I'd suggest upping the statisticss target on at least all of
> the join columns to at least 100. (Note that it's doing a nested loop
> thinking it will have only 2 rows but it actually has 22000 rows).
>
> On Thu, Feb 09, 2006 at 04:10:27PM +0100, Rafael Martinez Guerrero
> wrote:
> > Hello
> >
> > We are running an application via web that use a lot of time to
> perform
> > some operations. We are trying to find out if some of the sql
> statements
> > used are the reason of the slow speed.
> >
> > We have identified a sql that takes like 4-5000ms more than the second
> > slowest sql in out test server. I hope that we will get some help to
> try
> > to optimize it.
> >
> > Thanks in advance for any help.
> >
> [Snip]
>
>
> ---------------------------(end of broadcast)---------------------------
> TIP 1: if posting/reading through Usenet, please send an appropriate
>        subscribe-nomail command to majordomo@postgresql.org so that your
>        message can get through to the mailing list cleanly
>

--
Jim C. Nasby, Sr. Engineering Consultant      jnasby@pervasive.com
Pervasive Software      http://pervasive.com    work: 512-231-6117
vcard: http://jim.nasby.net/pervasive.vcf       cell: 512-569-9461

Re: Help with optimizing a sql statement

From
Rafael Martinez
Date:
On Thu, 2006-02-09 at 13:46 -0600, Jim C. Nasby wrote:
> I looked at the estimates for the table access methods and they all
> looked ok, so I think the statistics are pretty up-to-date; there just
> aren't enough of them for the planner to do a good job.
>

VACUUM ANALYZE runs 4 times every hour, so yes, statistics are
up-to-date. I will increase default_statistics_target tomorrow at work
and see what happens.

Thanks for your help.

--
Rafael Martinez, <r.m.guerrero@usit.uio.no>
Center for Information Technology Services
University of Oslo, Norway

PGP Public Key: http://folk.uio.no/rafael/


Re: Help with optimizing a sql statement

From
Tom Lane
Date:
Rafael Martinez Guerrero <r.m.guerrero@usit.uio.no> writes:
> WHERE ((ACL_2.RightName = 'OwnTicket'))
> AND ((CachedGroupMembers_4.MemberId = Principals_1.id))
> AND ((Groups_3.id = CachedGroupMembers_4.GroupId))
> AND ((Principals_1.Disabled = '0') or (Principals_1.Disabled = '0'))
> AND ((Principals_1.id != '1'))
> AND ((main.id = Principals_1.id))
> AND  ( (    ACL_2.PrincipalId = Groups_3.id AND ACL_2.PrincipalType =
> 'Group' AND (   Groups_3.Domain = 'SystemInternal' OR Groups_3.Domain =
> 'UserDefined' OR Groups_3.Domain = 'ACLEquivalence')) OR ( (
> (Groups_3.Domain = 'RT::Queue-Role' ) )  AND Groups_3.Type
> =ACL_2.PrincipalType) )
> AND (ACL_2.ObjectType = 'RT::System' OR (ACL_2.ObjectType = 'RT::Queue')
> )

Are you sure this WHERE clause really expresses your intent?  It seems
awfully oddly constructed.  Removing the redundant parens and clarifying
the layout, I get

WHERE ACL_2.RightName = 'OwnTicket'
AND CachedGroupMembers_4.MemberId = Principals_1.id
AND Groups_3.id = CachedGroupMembers_4.GroupId
AND (Principals_1.Disabled = '0' or Principals_1.Disabled = '0')
AND Principals_1.id != '1'
AND main.id = Principals_1.id
AND ( ( ACL_2.PrincipalId = Groups_3.id AND ACL_2.PrincipalType = 'Group' AND
        (Groups_3.Domain = 'SystemInternal' OR Groups_3.Domain = 'UserDefined' OR Groups_3.Domain = 'ACLEquivalence') )
     OR
      ( Groups_3.Domain = 'RT::Queue-Role' AND Groups_3.Type = ACL_2.PrincipalType )
    )
AND (ACL_2.ObjectType = 'RT::System' OR ACL_2.ObjectType = 'RT::Queue')

That next-to-last major AND clause seems a rather unholy mix of join and
restriction clauses; I wonder if it's not buggy in itself.  If it is
correct, I think most of the performance problem comes from the fact
that the planner can't break it down into independent clauses.  You
might try getting rid of the central OR in favor of doing a UNION of
two queries that comprise all the other terms.  More repetitious, but
would likely perform better.

BTW, what PG version is this?  It looks to me like it's doing some
manipulations of the WHERE clause that we got rid of a couple years ago.
If this is 7.4 or older then you really ought to be thinking about an
update.

            regards, tom lane

Re: Help with optimizing a sql statement

From
Rafael Martinez
Date:
On Thu, 2006-02-09 at 18:22 -0500, Tom Lane wrote:
> Rafael Martinez Guerrero <r.m.guerrero@usit.uio.no> writes:
> > WHERE ((ACL_2.RightName = 'OwnTicket'))
> > AND ((CachedGroupMembers_4.MemberId = Principals_1.id))
> > AND ((Groups_3.id = CachedGroupMembers_4.GroupId))
> > AND ((Principals_1.Disabled = '0') or (Principals_1.Disabled = '0'))
> > AND ((Principals_1.id != '1'))
> > AND ((main.id = Principals_1.id))
> > AND  ( (    ACL_2.PrincipalId = Groups_3.id AND ACL_2.PrincipalType =
> > 'Group' AND (   Groups_3.Domain = 'SystemInternal' OR Groups_3.Domain =
> > 'UserDefined' OR Groups_3.Domain = 'ACLEquivalence')) OR ( (
> > (Groups_3.Domain = 'RT::Queue-Role' ) )  AND Groups_3.Type
> > =ACL_2.PrincipalType) )
> > AND (ACL_2.ObjectType = 'RT::System' OR (ACL_2.ObjectType = 'RT::Queue')
> > )
>
> Are you sure this WHERE clause really expresses your intent?  It seems
> awfully oddly constructed.  Removing the redundant parens and clarifying
> the layout, I get
>
[............]

This is an application that we have not programmed, so I am not sure
what they are trying to do here. I will contact the developers. Tomorrow
I will try to test some of your suggestions.

> BTW, what PG version is this?  It looks to me like it's doing some
> manipulations of the WHERE clause that we got rid of a couple years ago.
> If this is 7.4 or older then you really ought to be thinking about an
> update.
>

We are running 7.4.8 in this server and will upgrade to 8.0.6 in a few
weeks.

Thanks.
--
Rafael Martinez, <r.m.guerrero@usit.uio.no>
Center for Information Technology Services
University of Oslo, Norway

PGP Public Key: http://folk.uio.no/rafael/


Re: Help with optimizing a sql statement

From
Vivek Khera
Date:
On Feb 9, 2006, at 6:36 PM, Rafael Martinez wrote:

> This is an application that we have not programmed, so I am not sure
> what they are trying to do here. I will contact the developers.
> Tomorrow
> I will try to test some of your suggestions.

well, obviously you're running RT... what you want to do is update
all your software to the latest versions.  in particular update RT to
3.4.5 and all the dependent modules to their latest.  We run with Pg
8.0 which is plenty fast.  one of these days I'll update to 8.1 but
need to test it out first.  i'm not sure how much RT has been tested
against 8.1


Re: Help with optimizing a sql statement

From
Greg Stark
Date:
Tom Lane <tgl@sss.pgh.pa.us> writes:

> Are you sure this WHERE clause really expresses your intent?  It seems
> awfully oddly constructed.  Removing the redundant parens and clarifying
> the layout, I get
...
> That next-to-last major AND clause seems a rather unholy mix of join and
> restriction clauses; I wonder if it's not buggy in itself.

FYI RT uses a perl module called SearchBuilder which constructs these queries
dynamically. So he's probably not really free to fiddle with the query all he
wants.

At the very least I would suggest checking the changelog for SearchBuilder for
more recent versions. There have been a lot of tweaks for working with
Postgres. In the past it really only worked properly with MySQL.

--
greg