Thread: Same SQL, 104296ms of difference between 7.4.12 and 8.0.7

Same SQL, 104296ms of difference between 7.4.12 and 8.0.7

From
Rafael Martinez Guerrero
Date:
Hello

I have a sql statement that takes 108489.780 ms with 8.0.7 in a
RHEL4/amd64linux server with 2xAMD Opteron(tm) Processor 275 2.00GHz /
8GB RAM and only 4193.588 ms with 7.4.12 in a RHEL3/386linux server with
2xIntel(R) Xeon(TM) CPU 2.40GHz / 4GB RAM.

Some information:

- There is no IO when I am running the sql, but it uses 99% of the cpu.
- I run VACUUM VERBOSE ANALYZE in both databases before the test.
- The databases are identical.
- No other jobs running when testing.
- Some different parameters between 7.4.12 and 8.0.7 :

7.4.12:
-------
shared_buffers = 114966   #(15% of ram)
sort_mem = 16384
vacuum_mem = 524288
wal_buffers = 64
checkpoint_segments = 16
effective_cache_size = 383220   #(50% ram)
random_page_cost = 3
default_statistics_target = 100

8.0.7:
------
shared_buffers = 250160   #(25% ram)
work_mem = 8192
maintenance_work_mem = 131072
wal_buffers = 128
checkpoint_segments = 64
effective_cache_size = 500321  #(50% ram)
random_page_cost = 3
default_statistics_target = 100

Any ideas of what I can test/configurate to find out why this happens?
Thanks in advance.


*******************
With 7.4.12
*******************
rtprod=# 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;



                                                                                    QUERYPLAN


                                                                       

 Unique  (cost=40250.00..40250.09 rows=1 width=695) (actual
time=3974.528..4182.343 rows=264 loops=1)
   ->  Sort  (cost=40250.00..40250.00 rows=1 width=695) (actual
time=3974.522..3992.487 rows=24697 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=33.67..40249.99 rows=1 width=695)
(actual time=37.793..3240.146 rows=24697 loops=1)
               ->  Nested Loop  (cost=33.67..40246.95 rows=1 width=699)
(actual time=37.754..2635.812 rows=24697 loops=1)
                     ->  Nested Loop  (cost=33.67..40242.47 rows=1
width=4) (actual time=37.689..2091.634 rows=24755 loops=1)
                           ->  Nested Loop  (cost=33.67..40225.72 rows=1
width=4) (actual time=37.663..1967.388 rows=54 loops=1)
                                 Join Filter:
(((("outer"."domain")::text = 'RT::Queue-Role'::text) OR
("inner".principalid = "outer".id)) AND ((("outer"."type")::text =
("inner".principaltype)::text) OR ("inner".principalid = "outer".id))
AND ((("outer"."domain")::text = 'RT::Queue-Role'::text) OR
(("inner".principaltype)::text = 'Group'::text)) AND
((("outer"."type")::text = ("inner".principaltype)::text) OR
(("inner".principaltype)::text = 'Group'::text)) AND
((("outer"."type")::text = ("inner".principaltype)::text) OR
(("outer"."domain")::text = 'SystemInternal'::text) OR
(("outer"."domain")::text = 'UserDefined'::text) OR
(("outer"."domain")::text = 'ACLEquivalence'::text)))
                                 ->  Index Scan using groups4, groups4,
groups4, groups4 on groups groups_3  (cost=0.00..2164.05 rows=15845
width=32) (actual time=0.041..43.636 rows=16160 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))
                                 ->  Materialize  (cost=33.67..34.15
rows=48 width=13) (actual time=0.001..0.040 rows=54 loops=16160)
                                       ->  Seq Scan on acl acl_2
(cost=0.00..33.67 rows=48 width=13) (actual time=0.016..0.989 rows=54
loops=1)
                                             Filter: (((rightname)::text
= 'OwnTicket'::text) AND (((objecttype)::text = 'RT::System'::text) OR
((objecttype)::text = 'RT::Queue'::text)))
                           ->  Index Scan using cachedgroupmembers3 on
cachedgroupmembers cachedgroupmembers_4  (cost=0.00..16.45 rows=23
width=8) (actual time=0.015..1.296 rows=458 loops=54)
                                 Index Cond: ("outer".id =
cachedgroupmembers_4.groupid)
                     ->  Index Scan using users_pkey on users main
(cost=0.00..4.47 rows=1 width=695) (actual time=0.007..0.009 rows=1
loops=24755)
                           Index Cond: (main.id = "outer".memberid)
               ->  Index Scan using principals_pkey on principals
principals_1  (cost=0.00..3.02 rows=1 width=4) (actual time=0.010..0.012
rows=1 loops=24697)
                     Index Cond: ("outer".id = principals_1.id)
                     Filter: ((disabled = 0::smallint) AND (id <> 1))
 Total runtime: 4193.588 ms
(21 rows)


*****************************
With 8.0.7
*****************************

rtprod=# 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;




                              QUERYPLAN

                                                                             
 Unique  (cost=164248.03..164250.91 rows=33 width=695) (actual
time=108249.642..108479.808 rows=264 loops=1)
   ->  Sort  (cost=164248.03..164248.11 rows=33 width=695) (actual
time=108249.637..108293.474 rows=24697 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=4702.57..164247.19 rows=33 width=695)
(actual time=2949.010..107407.145 rows=24697 loops=1)
               Join Filter: ((("inner".principalid = "outer".id) AND
(("inner".principaltype)::text = 'Group'::text) AND
((("outer"."domain")::text = 'SystemInternal'::text) OR
(("outer"."domain")::text = 'UserDefined'::text) OR
(("outer"."domain")::text = 'ACLEquivalence'::text))) OR
((("outer"."domain")::text = 'RT::Queue-Role'::text) AND
(("outer"."type")::text = ("inner".principaltype)::text)))
               ->  Hash Join  (cost=4667.85..51078.88 rows=62852
width=727) (actual time=649.028..13602.451 rows=513264 loops=1)
                     Hash Cond: ("outer".groupid = "inner".id)
                     ->  Merge Join  (cost=0.00..32353.73 rows=62852
width=699) (actual time=0.809..6644.928 rows=513264 loops=1)
                           Merge Cond: ("outer".id = "inner".memberid)
                           ->  Merge Join  (cost=0.00..6379.54
rows=15877 width=699) (actual time=0.118..911.395 rows=15866 loops=1)
                                 Merge Cond: ("outer".id = "inner".id)
                                 ->  Index Scan using users_pkey on
users main  (cost=0.00..1361.01 rows=15880 width=695) (actual
time=0.016..49.141 rows=15880 loops=1)
                                 ->  Index Scan using principals_pkey on
principals principals_1  (cost=0.00..4399.08 rows=168394 width=4)
(actual time=0.026..412.688 rows=168409 loops=1)
                                       Filter: ((disabled = 0::smallint)
AND (id <> 1))
                           ->  Index Scan using cachedgroupmembers2 on
cachedgroupmembers cachedgroupmembers_4  (cost=0.00..18647.25
rows=666758 width=8) (actual time=0.008..1513.877 rows=666754 loops=1)
                     ->  Hash  (cost=3094.48..3094.48 rows=152548
width=32) (actual time=637.618..637.618 rows=0 loops=1)
                           ->  Seq Scan on groups groups_3
(cost=0.00..3094.48 rows=152548 width=32) (actual time=0.017..333.669
rows=152548 loops=1)
               ->  Materialize  (cost=34.72..35.20 rows=48 width=13)
(actual time=0.001..0.077 rows=54 loops=513264)
                     ->  Seq Scan on acl acl_2  (cost=0.00..34.67
rows=48 width=13) (actual time=0.013..0.850 rows=54 loops=1)
                           Filter: (((rightname)::text =
'OwnTicket'::text) AND (((objecttype)::text = 'RT::System'::text) OR
((objecttype)::text = 'RT::Queue'::text)))
 Total runtime: 108486.306 ms
(21 rows)




--
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: Same SQL, 104296ms of difference between 7.4.12 and

From
Richard Huxton
Date:
Rafael Martinez Guerrero wrote:
> Hello
>
> I have a sql statement that takes 108489.780 ms with 8.0.7 in a
> RHEL4/amd64linux server with 2xAMD Opteron(tm) Processor 275 2.00GHz /
> 8GB RAM and only 4193.588 ms with 7.4.12 in a RHEL3/386linux server with
> 2xIntel(R) Xeon(TM) CPU 2.40GHz / 4GB RAM.
>
> Some information:
>
> - There is no IO when I am running the sql, but it uses 99% of the cpu.
> - I run VACUUM VERBOSE ANALYZE in both databases before the test.
> - The databases are identical.
> - No other jobs running when testing.
> - Some different parameters between 7.4.12 and 8.0.7 :
>
> 7.4.12:
> -------
> shared_buffers = 114966   #(15% of ram)
> sort_mem = 16384
> vacuum_mem = 524288
> wal_buffers = 64
> checkpoint_segments = 16
> effective_cache_size = 383220   #(50% ram)
> random_page_cost = 3
> default_statistics_target = 100
>
> 8.0.7:
> ------
> shared_buffers = 250160   #(25% ram)
> work_mem = 8192
> maintenance_work_mem = 131072
> wal_buffers = 128
> checkpoint_segments = 64
> effective_cache_size = 500321  #(50% ram)
> random_page_cost = 3
> default_statistics_target = 100
>
> Any ideas of what I can test/configurate to find out why this happens?
> Thanks in advance.

I haven't looked in detail at the plans, but what stands out to me is
that you've got a sort with a lot of columns and you've halved sort_mem
(work_mem). Try increasing it (perhaps to 32000 even).
    set work_mem = 32000;

Give that a quick go and see what happens. If it doesn't work, we'll
look at the plans in more detail.
--
   Richard Huxton
   Archonet Ltd

Re: Same SQL, 104296ms of difference between 7.4.12 and

From
Rafael Martinez Guerrero
Date:
On Fri, 2006-04-07 at 15:31, Richard Huxton wrote:
> Rafael Martinez Guerrero wrote:
> > Hello
> >
> > I have a sql statement that takes 108489.780 ms with 8.0.7 in a
> > RHEL4/amd64linux server with 2xAMD Opteron(tm) Processor 275 2.00GHz /
> > 8GB RAM and only 4193.588 ms with 7.4.12 in a RHEL3/386linux server with
> > 2xIntel(R) Xeon(TM) CPU 2.40GHz / 4GB RAM.
> >
> > Some information:
> >
> > - There is no IO when I am running the sql, but it uses 99% of the cpu.
> > - I run VACUUM VERBOSE ANALYZE in both databases before the test.
> > - The databases are identical.
> > - No other jobs running when testing.
> > - Some different parameters between 7.4.12 and 8.0.7 :
> >
> > 7.4.12:
> > -------
> > shared_buffers = 114966   #(15% of ram)
> > sort_mem = 16384
> > vacuum_mem = 524288
> > wal_buffers = 64
> > checkpoint_segments = 16
> > effective_cache_size = 383220   #(50% ram)
> > random_page_cost = 3
> > default_statistics_target = 100
> >
> > 8.0.7:
> > ------
> > shared_buffers = 250160   #(25% ram)
> > work_mem = 8192
> > maintenance_work_mem = 131072
> > wal_buffers = 128
> > checkpoint_segments = 64
> > effective_cache_size = 500321  #(50% ram)
> > random_page_cost = 3
> > default_statistics_target = 100
> >
> > Any ideas of what I can test/configurate to find out why this happens?
> > Thanks in advance.
>
> I haven't looked in detail at the plans, but what stands out to me is
> that you've got a sort with a lot of columns and you've halved sort_mem
> (work_mem). Try increasing it (perhaps to 32000 even).
>     set work_mem = 32000;
>
> Give that a quick go and see what happens. If it doesn't work, we'll
> look at the plans in more detail.

I know that this SQL could be done in a much better way, but I can not
change it at the moment.

work_mem = 16384:
-----------------
After restarting the database and running the explain two times:
107911.229 ms

work_mem = 32768:
-----------------
After restarting the database and running the explain two times:
103988.337 ms


--
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: Same SQL, 104296ms of difference between 7.4.12 and

From
Richard Huxton
Date:
Rafael Martinez Guerrero wrote:
>>> Any ideas of what I can test/configurate to find out why this happens?
>>> Thanks in advance.
>> I haven't looked in detail at the plans, but what stands out to me is
>> that you've got a sort with a lot of columns and you've halved sort_mem
>> (work_mem). Try increasing it (perhaps to 32000 even).
>>     set work_mem = 32000;
>>
>> Give that a quick go and see what happens. If it doesn't work, we'll
>> look at the plans in more detail.
>
> I know that this SQL could be done in a much better way, but I can not
> change it at the moment.
>
> work_mem = 16384:
> -----------------
> After restarting the database and running the explain two times:
> 107911.229 ms
>
> work_mem = 32768:
> -----------------
> After restarting the database and running the explain two times:
> 103988.337 ms

Damn! I hate it when I have to actually work at a problem :-)


Well, the first thing that strikes me is that the row estimates are
terrible for 7.4.12 (which runs quickly) and much better for 8.0.7
(which runs slowly). Which suggests you were lucky before.

The second thing I notice is the bit that goes: Materialize ... Seq Scan
on acl acl_2. If you compare the two you'll see that the 7.4 version
loops 16,160 times but 8.0 loops 513,264 times.

This is a bad choice, and I'm guessing it's made because it gets the row
estimate wrong:
Hash Join  (cost=4667.85..51078.88 rows=62852 width=727) (actual
time=649.028..13602.451 rows=513264 loops=1)

That's the comparison Groups_3.id = CachedGroupMembers_4.GroupId if I'm
reading this correctly. Is there anything unusual about those two columns?
--
   Richard Huxton
   Archonet Ltd

Re: Same SQL, 104296ms of difference between 7.4.12 and

From
Rafael Martinez
Date:
On Fri, 2006-04-07 at 16:41 +0200, Gábriel Ákos wrote:

> >
> > Any ideas of what I can test/configurate to find out why this happens?
> > Thanks in advance.
>
> Increase work_mem to 50% of memory, and don't care about
> maintenance_work_mem and effective_cache_size, they don't matter in this
> case.
>

The problem is not the amount of memory. It works much faster with only
16M and 7.4.12 than 8.0.7.

--
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: Same SQL, 104296ms of difference between 7.4.12 and 8.0.7

From
Tom Lane
Date:
Rafael Martinez Guerrero <r.m.guerrero@usit.uio.no> writes:
> I have a sql statement that takes 108489.780 ms with 8.0.7 in a
> RHEL4/amd64linux server with 2xAMD Opteron(tm) Processor 275 2.00GHz /
> 8GB RAM and only 4193.588 ms with 7.4.12 in a RHEL3/386linux server with
> 2xIntel(R) Xeon(TM) CPU 2.40GHz / 4GB RAM.

I think you've discovered a planner regression.
Simplified test case using the regression database:

explain select * from tenk1 a, tenk1 b
where (a.ten = b.ten and (a.unique1 = 100 or a.unique1 = 101))
   or (a.hundred = b.hundred and a.unique1 = 42);

7.4:
 Nested Loop  (cost=0.00..2219.74 rows=4 width=488)
   Join Filter: ((("outer".hundred = "inner".hundred) OR ("outer".ten = "inner".ten)) AND (("outer".unique1 = 42) OR
("outer".ten= "inner".ten)) AND (("outer".hundred = "inner".hundred) OR ("outer".unique1 = 100) OR ("outer".unique1 =
101)))
   ->  Index Scan using tenk1_unique1, tenk1_unique1, tenk1_unique1 on tenk1 a (cost=0.00..18.04 rows=3 width=244)
         Index Cond: ((unique1 = 42) OR (unique1 = 100) OR (unique1 = 101))
   ->  Seq Scan on tenk1 b  (cost=0.00..458.24 rows=10024 width=244)
(5 rows)

8.0:
 Nested Loop  (cost=810.00..6671268.00 rows=2103 width=488)
   Join Filter: ((("outer".ten = "inner".ten) AND (("outer".unique1 = 100) OR ("outer".unique1 = 101))) OR
(("outer".hundred= "inner".hundred) AND ("outer".unique1 = 42))) 
   ->  Seq Scan on tenk1 a  (cost=0.00..458.00 rows=10000 width=244)
   ->  Materialize  (cost=810.00..1252.00 rows=10000 width=244)
         ->  Seq Scan on tenk1 b  (cost=0.00..458.00 rows=10000 width=244)
(5 rows)

Note the failure to pull out the unique1 conditions from the join clause
and use them with the index.  I didn't bother to do EXPLAIN ANALYZE;
this plan obviously sucks compared to the other.

8.1:
TRAP: FailedAssertion("!(!restriction_is_or_clause((RestrictInfo *) orarg))", File: "indxpath.c", Line: 479)
LOG:  server process (PID 12201) was terminated by signal 6
server closed the connection unexpectedly

Oh dear.

            regards, tom lane

Re: Same SQL, 104296ms of difference between 7.4.12 and 8.0.7

From
Tom Lane
Date:
I wrote:
> Rafael Martinez Guerrero <r.m.guerrero@usit.uio.no> writes:
>> I have a sql statement that takes 108489.780 ms with 8.0.7 in a
>> RHEL4/amd64linux server with 2xAMD Opteron(tm) Processor 275 2.00GHz /
>> 8GB RAM and only 4193.588 ms with 7.4.12 in a RHEL3/386linux server with
>> 2xIntel(R) Xeon(TM) CPU 2.40GHz / 4GB RAM.

> I think you've discovered a planner regression.
> Simplified test case using the regression database:

> explain select * from tenk1 a, tenk1 b
> where (a.ten = b.ten and (a.unique1 = 100 or a.unique1 = 101))
>    or (a.hundred = b.hundred and a.unique1 = 42);

I've repaired the assertion crash in 8.1/HEAD, but I don't think it's
practical to teach 8.0 to optimize queries like this nicely.  The reason
7.4 can do it is that 7.4 forces the WHERE condition into CNF, ie

  (a.hundred = b.hundred OR a.ten = b.ten) AND
  (a.unique1 = 42 OR a.ten = b.ten) AND
  (a.hundred = b.hundred OR a.unique1 = 100 OR a.unique1 = 101) AND
  (a.unique1 = 42 OR a.unique1 = 100 OR a.unique1 = 101)

from which it's easy to extract the index condition for A.  We decided
that forcing to CNF wasn't such a hot idea, so 8.0 and later don't do
it, but 8.0's logic for extracting index conditions from joinquals isn't
up to the problem of handling sub-ORs.  Fixing that looks like a larger
change than I care to back-patch into an old release.

My recommendation is to update to 8.1.4 when it comes out.

            regards, tom lane

Re: Same SQL, 104296ms of difference between 7.4.12 and

From
Rafael Martinez
Date:
On Fri, 2006-04-07 at 13:36 -0400, Tom Lane wrote:
> I wrote:
> > Rafael Martinez Guerrero <r.m.guerrero@usit.uio.no> writes:
> >> I have a sql statement that takes 108489.780 ms with 8.0.7 in a
> >> RHEL4/amd64linux server with 2xAMD Opteron(tm) Processor 275 2.00GHz /
> >> 8GB RAM and only 4193.588 ms with 7.4.12 in a RHEL3/386linux server with
> >> 2xIntel(R) Xeon(TM) CPU 2.40GHz / 4GB RAM.
>
> > I think you've discovered a planner regression.
> > Simplified test case using the regression database:
>
> > explain select * from tenk1 a, tenk1 b
> > where (a.ten = b.ten and (a.unique1 = 100 or a.unique1 = 101))
> >    or (a.hundred = b.hundred and a.unique1 = 42);
>
> I've repaired the assertion crash in 8.1/HEAD, but I don't think it's
> practical to teach 8.0 to optimize queries like this nicely.  The reason
> 7.4 can do it is that 7.4 forces the WHERE condition into CNF, ie
>
[..................]

Tom, thank you very much for your help. As I suspected this was a more
complicated problem than the configuration of some parameters :( . Good
that we have found out this now and not after the upgrade.

All our upgrade plans and testing for all our databases have been done
for/with 8.0.x (yes, I know 8.1.x is much better, but I am working in a
conservative place from the sysadm point of view). We will have to
change our plans and go for 8.1 if we want this to work.

> My recommendation is to update to 8.1.4 when it comes out.

Any idea about when 8.1.4 will be released?
Thanks again.

--
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/