27 second plan times - Mailing list pgsql-hackers

From Gregory Stark
Subject 27 second plan times
Date
Msg-id 87647qajgt.fsf@oxford.xeocode.com
Whole thread Raw
Responses Re: 27 second plan times
Re: 27 second plan times
Re: 27 second plan times
List pgsql-hackers
Following up on some complaints we've had about extremely large plan times for
large partitioned tables I've been doing some profiling. I've constructed a
situation where it takes upwards of 30 seconds to plan a simple query like:

postgres=# explain select * from a where i between 999 and 1001;                             QUERY PLAN
            
 
----------------------------------------------------------------------Result  (cost=0.00..8.63 rows=58 width=108)  ->
Append (cost=0.00..8.63 rows=58 width=108)        ->  Seq Scan on a  (cost=0.00..1.01 rows=1 width=108)
Filter:((i >= 999) AND (i <= 1001))        ->  Seq Scan on a997 a  (cost=0.00..1.27 rows=1 width=108)
Filter:((i >= 999) AND (i <= 1001))        ->  Seq Scan on a998 a  (cost=0.00..1.27 rows=1 width=108)
Filter:((i >= 999) AND (i <= 1001))        ->  Seq Scan on a999 a  (cost=0.00..1.27 rows=18 width=108)
Filter:((i >= 999) AND (i <= 1001))        ->  Seq Scan on a1000 a  (cost=0.00..1.27 rows=18 width=108)
Filter:((i >= 999) AND (i <= 1001))        ->  Seq Scan on a1001 a  (cost=0.00..1.27 rows=18 width=108)
Filter:((i >= 999) AND (i <= 1001))        ->  Seq Scan on a1002 a  (cost=0.00..1.27 rows=1 width=108)
Filter:((i >= 999) AND (i <= 1001))
 
(16 rows)

Time: 46324.627 ms

Table "a" is a parent table with 2,000 partitions each of which have 102
columns, two of which are covered by constraints of the form "WHERE i BETWEEN
90 AND 110".

The gprof output is pretty damning:

Each sample counts as 0.01 seconds. %   cumulative   self              self     total           time   seconds
seconds   calls   s/call   s/call  name    62.58    203.76   203.76 21,474,937     0.00     0.00  SearchCatCache 9.01
233.08    29.32  1,923,789     0.00     0.00  list_nth_cell 5.34    250.46    17.38  2386465     0.00     0.00
pgstat_initstats2.80    259.57     9.11 235691652     0.00     0.00  AllocSetAlloc 1.95    265.91     6.34 219852840
0.00     0.00  nocachegetattr 1.19    269.78     3.87 256569078     0.00     0.00  FunctionCall2 0.74    272.18
2.40107923848     0.00     0.00  MemoryContextAllocZeroAligned
 


The SearchCatCache here is the one in get_attavgwidth called to estimate the
relation width. There are 200k attributes being measured here but I'm not
clear why it's causing 21M calls.

The first thing that comes to mind is that we're doing the
constraint_exclusion code *after* estimating the width of the relations we're
going to exclude. If we push the constraint exclusion up a few lines the
planning time goes down the 1.7s.

I think there's still a problem here with some kind of n^2 behaviour for
appends of very wide tables but I haven't quite nailed it yet. In any case is
there any reason not to make the following small change to move the constraint
exclusion ahead of the size estimates and index checks and save ourselves
potentially a lot of work?

Index: allpaths.c
===================================================================
RCS file: /home/stark/src/REPOSITORY/pgsql/src/backend/optimizer/path/allpaths.c,v
retrieving revision 1.161
diff -c -r1.161 allpaths.c
*** allpaths.c    22 Feb 2007 22:00:23 -0000    1.161
--- allpaths.c    20 Apr 2007 18:12:40 -0000
***************
*** 196,215 **** static void set_plain_rel_pathlist(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte) {
-     /* Mark rel with estimated output rows, width, etc */
-     set_baserel_size_estimates(root, rel);
- 
-     /* Test any partial indexes of rel for applicability */
-     check_partial_indexes(root, rel);
- 
-     /*
-      * Check to see if we can extract any restriction conditions from join
-      * quals that are OR-of-AND structures.  If so, add them to the rel's
-      * restriction list, and recompute the size estimates.
-      */
-     if (create_or_index_quals(root, rel))
-         set_baserel_size_estimates(root, rel);
-      /*      * If we can prove we don't need to scan the rel via constraint exclusion,      * set up a single dummy
pathfor it.  (Rather than inventing a special
 
--- 196,201 ----
***************
*** 228,233 ****
--- 214,233 ----         return;     } 
+     /* Mark rel with estimated output rows, width, etc */
+     set_baserel_size_estimates(root, rel);
+ 
+     /* Test any partial indexes of rel for applicability */
+     check_partial_indexes(root, rel);
+ 
+     /*
+      * Check to see if we can extract any restriction conditions from join
+      * quals that are OR-of-AND structures.  If so, add them to the rel's
+      * restriction list, and recompute the size estimates.
+      */
+     if (create_or_index_quals(root, rel))
+         set_baserel_size_estimates(root, rel);
+      /*      * Generate paths and add them to the rel's pathlist.      *




--  Gregory Stark EnterpriseDB          http://www.enterprisedb.com



pgsql-hackers by date:

Previous
From: Neil Conway
Date:
Subject: Re: Improving deadlock error messages
Next
From: "Nicolas Barbier"
Date:
Subject: Re: Eliminating unnecessary left joins