Thread: Postgres8.0 planner chooses WRONG plan

Postgres8.0 planner chooses WRONG plan

From
Pallav Kalva
Date:
Hi ,


   I am having problem optimizing this query, Postgres optimizer uses a
plan which invloves seq-scan on a table. And when I choose a option to
disable seq-scan it uses index-scan and obviously the query is much faster.
   All tables are daily vacummed and analyzed as per docs.

  Why cant postgres use index-scan ?


Postgres Version:8.0.2
Platform : Fedora

Here is the explain analyze output. Let me know if any more information
is needed.  Can we make postgres use index scan for this query ?

Thanks!
Pallav.


-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------


explain analyze
select * from provisioning.alerts where countystate = 'FL' and countyno
= '099' and status = 'ACTIVE' ;

                                                                   QUERY
PLAN

--------------------------------------------------------------------------------------------------------------------------------------------------


Nested Loop  (cost=3.45..15842.17 rows=1 width=125) (actual
time=913.491..18992.009 rows=110 loops=1)
  ->  Nested Loop  (cost=3.45..15838.88 rows=1 width=86) (actual
time=913.127..18958.482 rows=110 loops=1)
        ->  Hash Join  (cost=3.45..15835.05 rows=1 width=82) (actual
time=913.093..18954.951 rows=110 loops=1)
              Hash Cond: ("outer".fkserviceinstancestatusid =
"inner".serviceinstancestatusid)
              ->  Hash Join  (cost=2.38..15833.96 rows=2 width=74)
(actual time=175.139..18952.830 rows=358 loops=1)
                    Hash Cond: ("outer".fkserviceofferingid =
"inner".serviceofferingid)
                    ->  Seq Scan on serviceinstance si
(cost=0.00..15831.52 rows=7 width=78) (actual time=174.430..18948.210
rows=358 loops=1)
                          Filter: (((subplan) = 'FL'::text) AND
((subplan) = '099'::text))
                          SubPlan
                            ->  Result  (cost=0.00..0.01 rows=1 width=0)
(actual time=0.090..0.093 rows=1 loops=3923)
                            ->  Result  (cost=0.00..0.01 rows=1 width=0)
(actual time=0.058..0.061 rows=1 loops=265617)
                    ->  Hash  (cost=2.38..2.38 rows=3 width=4) (actual
time=0.444..0.444 rows=0 loops=1)
                          ->  Hash Join  (cost=1.08..2.38 rows=3
width=4) (actual time=0.312..0.428 rows=1 loops=1)
                                Hash Cond: ("outer".fkserviceid =
"inner".serviceid)
                                ->  Seq Scan on serviceoffering so
(cost=0.00..1.18 rows=18 width=8) (actual time=0.005..0.068 rows=18
loops=1)
                                ->  Hash  (cost=1.07..1.07 rows=1
width=4) (actual time=0.036..0.036 rows=0 loops=1)
                                      ->  Seq Scan on service s
(cost=0.00..1.07 rows=1 width=4) (actual time=0.014..0.019 rows=1 loops=1)
                                            Filter: (servicename =
'alert'::text)
              ->  Hash  (cost=1.06..1.06 rows=1 width=16) (actual
time=0.044..0.044 rows=0 loops=1)
                    ->  Seq Scan on serviceinstancestatus sis
(cost=0.00..1.06 rows=1 width=16) (actual time=0.017..0.024 rows=1 loops=1)
                          Filter: (status = 'ACTIVE'::text)
        ->  Index Scan using pk_account_accountid on account a
(cost=0.00..3.82 rows=1 width=8) (actual time=0.012..0.016 rows=1
loops=110)
              Index Cond: ("outer".fkaccountid = a.accountid)
  ->  Index Scan using pk_contact_contactid on contact c
(cost=0.00..3.24 rows=1 width=47) (actual time=0.014..0.018 rows=1
loops=110)
        Index Cond: ("outer".fkcontactid = c.contactid)
  SubPlan
    ->  Result  (cost=0.00..0.01 rows=1 width=0) (actual
time=0.072..0.075 rows=1 loops=110)
    ->  Result  (cost=0.00..0.01 rows=1 width=0) (actual
time=0.079..0.082 rows=1 loops=110)
    ->  Result  (cost=0.00..0.01 rows=1 width=0) (actual
time=0.086..0.089 rows=1 loops=110)
Total runtime: 18992.694 ms
(30 rows)

Time: 18996.203 ms

--> As you can see the ->  Seq Scan on serviceinstance si
(cost=0.00..15831.52 rows=7 width=78) (actual time=174.430..18948.210
rows=358 loops=1) was taking too long .
   same query when i disable the seq-scan it uses index-scan and its
much faster now

set enable_seqscan=false;
SET
Time: 0.508 ms
explain analyze
select * from provisioning.alerts where countystate = 'FL' and countyno
= '099' and status = 'ACTIVE' ;


QUERY PLAN

-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------


Nested Loop  (cost=9.10..16676.10 rows=1 width=125) (actual
time=24.792..3898.939 rows=110 loops=1)
  ->  Nested Loop  (cost=9.10..16672.81 rows=1 width=86) (actual
time=24.383..3862.025 rows=110 loops=1)
        ->  Hash Join  (cost=9.10..16668.97 rows=1 width=82) (actual
time=24.351..3858.351 rows=110 loops=1)
              Hash Cond: ("outer".fkserviceofferingid =
"inner".serviceofferingid)
              ->  Nested Loop  (cost=0.00..16659.85 rows=2 width=86)
(actual time=8.449..3841.260 rows=110 loops=1)
                    ->  Index Scan using
pk_serviceinstancestatus_serviceinstancestatusid on
serviceinstancestatus sis  (cost=0.00..3.07 rows=1 width=16) (actual
time=3.673..3.684 rows=1 loops=1)
                          Filter: (status = 'ACTIVE'::text)
                    ->  Index Scan using
idx_serviceinstance_fkserviceinstancestatusid on serviceinstance si
(cost=0.00..16656.76 rows=2 width=78) (actual time=4.755..3836.399
rows=110 loops=1)
                          Index Cond: (si.fkserviceinstancestatusid =
"outer".serviceinstancestatusid)
                          Filter: (((subplan) = 'FL'::text) AND
((subplan) = '099'::text))
                          SubPlan
                            ->  Result  (cost=0.00..0.01 rows=1 width=0)
(actual time=0.125..0.128 rows=1 loops=1283)
                            ->  Result  (cost=0.00..0.01 rows=1 width=0)
(actual time=0.083..0.086 rows=1 loops=26146)
              ->  Hash  (cost=9.09..9.09 rows=3 width=4) (actual
time=15.661..15.661 rows=0 loops=1)
                    ->  Nested Loop  (cost=0.00..9.09 rows=3 width=4)
(actual time=15.617..15.637 rows=1 loops=1)
                          ->  Index Scan using uk_service_servicename on
service s  (cost=0.00..3.96 rows=1 width=4) (actual time=11.231..11.236
rows=1 loops=1)
                                Index Cond: (servicename = 'alert'::text)
                          ->  Index Scan using
idx_serviceoffering_fkserviceid on serviceoffering so  (cost=0.00..5.09
rows=3 width=8) (actual time=4.366..4.371 rows=1 loops=1)
                                Index Cond: ("outer".serviceid =
so.fkserviceid)
        ->  Index Scan using pk_account_accountid on account a
(cost=0.00..3.82 rows=1 width=8) (actual time=0.013..0.017 rows=1
loops=110)
              Index Cond: ("outer".fkaccountid = a.accountid)
  ->  Index Scan using pk_contact_contactid on contact c
(cost=0.00..3.24 rows=1 width=47) (actual time=0.013..0.017 rows=1
loops=110)
        Index Cond: ("outer".fkcontactid = c.contactid)
  SubPlan
    ->  Result  (cost=0.00..0.01 rows=1 width=0) (actual
time=0.081..0.084 rows=1 loops=110)
    ->  Result  (cost=0.00..0.01 rows=1 width=0) (actual
time=0.088..0.091 rows=1 loops=110)
    ->  Result  (cost=0.00..0.01 rows=1 width=0) (actual
time=0.098..0.101 rows=1 loops=110)
Total runtime: 3899.589 ms
(28 rows)


Here is the view definition
-------------------------------

      View "provisioning.alerts"
     Column       |  Type   | Modifiers
-------------------+---------+-----------
serviceinstanceid | integer |
accountid         | integer |
firstname         | text    |
lastname          | text    |
email             | text    |
status            | text    |
affiliate         | text    |
affiliatesub      | text    |
domain            | text    |
countyno          | text    |
countystate       | text    |
listingtype       | text    |
View definition:
SELECT si.serviceinstanceid, a.accountid, c.firstname, c.lastname,
c.email, sis.status, si.affiliate, si.affiliatesub, si."domain",
              ( SELECT get_parametervalue(si.serviceinstanceid,
'countyNo'::text) AS get_parametervalue) AS countyno,
             ( SELECT get_parametervalue(si.serviceinstanceid,
'countyState'::text) AS get_parametervalue) AS countystate,
             ( SELECT get_parametervalue(si.serviceinstanceid,
'listingType'::text) AS get_parametervalue) AS listingtype
  FROM provisioning.account a, common.contact c, provisioning.service s,
provisioning.serviceoffering so, provisioning.serviceinstance si,
provisioning.serviceinstancestatus sis
 WHERE si.fkserviceofferingid = so.serviceofferingid
 AND si.fkserviceinstancestatusid = sis.serviceinstancestatusid
AND s.serviceid = so.fkserviceid
AND a.fkcontactid = c.contactid
AND si.fkaccountid = a.accountid
AND s.servicename = 'alert'::text;

Function Definition
----------------------

CREATE OR REPLACE FUNCTION get_parametervalue(v_fkserviceinstanceid
integer, v_name text) RETURNS TEXT AS $$
DECLARE
       v_value        text;
BEGIN
       SELECT  p.value
       INTO    v_value
       FROM    provisioning.serviceinstanceparameter sip,
common.parameter p
       WHERE   fkserviceinstanceid = v_fkserviceinstanceid
       AND     sip.fkparameterid = p.parameterid
       AND     p.name = v_name;

       RETURN  v_value;

END

Serviceinstance table stats
-----------------------------

select relname, relpages, reltuples from pg_class where relname =
'serviceinstance';
    relname     | relpages | reltuples
-----------------+----------+-----------
serviceinstance |     5207 |    265613

$$ language plpgsql





Re: Postgres8.0 planner chooses WRONG plan

From
Tom Lane
Date:
Pallav Kalva <pkalva@livedatagroup.com> writes:
>    I am having problem optimizing this query,

Get rid of the un-optimizable function inside the view.  You've
converted something that should be a join into an unreasonably large
number of function calls.

>                     ->  Seq Scan on serviceinstance si
> (cost=0.00..15831.52 rows=7 width=78) (actual time=174.430..18948.210
> rows=358 loops=1)
>                           Filter: (((subplan) = 'FL'::text) AND
> ((subplan) = '099'::text))
>                           SubPlan
>                             ->  Result  (cost=0.00..0.01 rows=1 width=0)
> (actual time=0.090..0.093 rows=1 loops=3923)
>                             ->  Result  (cost=0.00..0.01 rows=1 width=0)
> (actual time=0.058..0.061 rows=1 loops=265617)

The bulk of the cost here is in the second subplan (0.061 * 265617 =
16202.637 msec total runtime), and there's not a darn thing Postgres
can do to improve this because the work is all down inside a "black box"
function.  In fact the planner does not even know that the function call
is expensive, else it would have preferred a plan that requires fewer
evaluations of the function.  The alternative plan you show is *not*
faster "because it's an indexscan"; it's faster because get_parametervalue
is evaluated fewer times.

The useless sub-SELECTs atop the function calls are adding their own
little increment of wasted time, too.  I'm not sure how bad that is
relative to the function calls, but it's certainly not helping.

            regards, tom lane

Re: Postgres8.0 planner chooses WRONG plan

From
Pallav Kalva
Date:
Hi Tom,

     Thanks! for your input, the view was written first without using
the function but its an ugly big with all the joins and its much slower
that way. Below is the view without the function and its explain analzye
output , as you can see the it takes almost 2 min to run this query with
this view . Is there any way to optimize or make changes to this view ?

Thanks!
Pallav.


View Definition
-------------------

create or replace view provisioning.alertserviceinstanceold as
SELECT services.serviceinstanceid, a.accountid, c.firstname, c.lastname,
c.email, services.countyno, services.countystate, services.listingtype
AS listingtypename, services.status, services.affiliate,
services.affiliatesub, services."domain"
   FROM provisioning.account a
   JOIN common.contact c ON a.fkcontactid = c.contactid
   JOIN ( SELECT p1.serviceinstanceid, p1.accountid, p1.countyno,
p2.countystate, p3.listingtype, p1.status, p1.affiliate,
p1.affiliatesub, p1."domain"
      FROM ( SELECT si.serviceinstanceid, si.affiliate, si.affiliatesub,
si."domain", si.fkaccountid AS accountid, p.value AS countyno, sis.status
              FROM provisioning.service s
         JOIN provisioning.serviceoffering so ON s.serviceid =
so.fkserviceid
    JOIN provisioning.serviceinstance si ON so.serviceofferingid =
si.fkserviceofferingid
   JOIN provisioning.serviceinstancestatus sis ON
si.fkserviceinstancestatusid = sis.serviceinstancestatusid
   JOIN provisioning.serviceinstanceparameter sip ON
si.serviceinstanceid = sip.fkserviceinstanceid
   JOIN common.parameter p ON sip.fkparameterid = p.parameterid
  WHERE s.servicename = 'alert'::text AND p.name = 'countyNo'::text) p1
   JOIN ( SELECT si.serviceinstanceid, si.affiliate, si.affiliatesub,
si."domain", si.fkaccountid AS accountid, p.value AS countystate, sis.status
              FROM provisioning.service s
         JOIN provisioning.serviceoffering so ON s.serviceid =
so.fkserviceid
    JOIN provisioning.serviceinstance si ON so.serviceofferingid =
si.fkserviceofferingid
   JOIN provisioning.serviceinstancestatus sis ON
si.fkserviceinstancestatusid = sis.serviceinstancestatusid
   JOIN provisioning.serviceinstanceparameter sip ON
si.serviceinstanceid = sip.fkserviceinstanceid
   JOIN common.parameter p ON sip.fkparameterid = p.parameterid
  WHERE s.servicename = 'alert'::text AND p.name = 'countyState'::text)
p2 ON p1.accountid = p2.accountid AND p1.serviceinstanceid =
p2.serviceinstanceid
   JOIN ( SELECT si.serviceinstanceid, si.affiliate, si.affiliatesub,
si."domain", si.fkaccountid AS accountid, p.value AS listingtype, sis.status
         FROM provisioning.service s
    JOIN provisioning.serviceoffering so ON s.serviceid = so.fkserviceid
   JOIN provisioning.serviceinstance si ON so.serviceofferingid =
si.fkserviceofferingid
   JOIN provisioning.serviceinstancestatus sis ON
si.fkserviceinstancestatusid = sis.serviceinstancestatusid
   JOIN provisioning.serviceinstanceparameter sip ON
si.serviceinstanceid = sip.fkserviceinstanceid
   JOIN common.parameter p ON sip.fkparameterid = p.parameterid
  WHERE s.servicename = 'alert'::text AND p.name = 'listingType'::text)
p3 ON p2.accountid = p3.accountid AND p2.serviceinstanceid =
p3.serviceinstanceid) services
ON a.accountid = services.accountid
ORDER BY services.serviceinstanceid;

Explain Analyze
------------------
explain analyze
select * from provisioning.alertserviceinstanceold where countystate =
'FL' and countyno = '099' and status = 'ACTIVE' ;


    
QUERY PLAN


----------------------------------------------------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------------------------
 Subquery Scan alertserviceinstanceold  (cost=31954.24..31954.25 rows=1
width=328) (actual time=113485.801..113487.024 rows=110 loops=1)
   ->  Sort  (cost=31954.24..31954.24 rows=1 width=152) (actual
time=113485.787..113486.123 rows=110 loops=1)
         Sort Key: si.serviceinstanceid
         ->  Hash Join  (cost=20636.38..31954.23 rows=1 width=152)
(actual time=109721.688..113485.311 rows=110 loops=1)
               Hash Cond: ("outer".accountid = "inner".fkaccountid)
               ->  Hash Join  (cost=6595.89..16770.25 rows=228696
width=47) (actual time=1742.592..4828.396 rows=229855 loops=1)
                     Hash Cond: ("outer".contactid = "inner".fkcontactid)
                     ->  Seq Scan on contact c  (cost=0.00..4456.96
rows=228696 width=47) (actual time=0.006..1106.459 rows=229868 loops=1)
                     ->  Hash  (cost=6024.11..6024.11 rows=228711
width=8) (actual time=1742.373..1742.373 rows=0 loops=1)
                           ->  Seq Scan on account a
(cost=0.00..6024.11 rows=228711 width=8) (actual time=0.010..990.597
rows=229855 loops=1)
               ->  Hash  (cost=14040.49..14040.49 rows=1 width=117)
(actual time=107911.397..107911.397 rows=0 loops=1)
                     ->  Nested Loop  (cost=10.34..14040.49 rows=1
width=117) (actual time=1185.383..107910.738 rows=110 loops=1)
                           ->  Nested Loop  (cost=10.34..14037.45 rows=1
width=112) (actual time=1185.278..107898.885 rows=550 loops=1)
                                 ->  Hash Join  (cost=10.34..14033.98
rows=1 width=124) (actual time=1185.224..107888.542 rows=110 loops=1)
                                       Hash Cond:
("outer".fkserviceofferingid = "inner".serviceofferingid)
                                       ->  Hash Join
(cost=7.96..14031.58 rows=1 width=128) (actual time=1184.490..107886.329
rows=110 loops=1)
                                             Hash Cond:
("outer".fkserviceinstancestatusid = "inner".serviceinstancestatusid)
                                             ->  Nested Loop
(cost=6.90..14030.50 rows=1 width=132) (actual time=1184.151..107884.302
rows=110 loops=1)
                                                   Join Filter:
("outer".fkaccountid = "inner".fkaccountid)
                                                   ->  Nested Loop
(cost=6.90..14025.09 rows=1 width=116) (actual time=1184.123..107880.635
rows=110 loops=1)
                                                         Join Filter:
(("outer".fkaccountid = "inner".fkaccountid) AND
("outer".serviceinstanceid = "inner".serviceinstanceid))
                                                         ->  Hash Join
(cost=3.45..636.39 rows=1 width=95) (actual time=85.524..293.387
rows=226 loops=1)
                                                               Hash
Cond: ("outer".fkserviceinstancestatusid = "inner".serviceinstancestatusid)
                                                               ->  Hash
Join  (cost=2.38..635.29 rows=4 width=87) (actual time=6.894..289.000
rows=663 loops=1)

Hash Cond: ("outer".fkserviceofferingid = "inner".serviceofferingid)
                                                                     ->
Nested Loop  (cost=0.00..632.75 rows=23 width=91) (actual
time=6.176..281.620 rows=663 loops=1)

->  Nested Loop  (cost=0.00..508.26 rows=23 width=13) (actual
time=6.138..221.590 rows=663 loops=1)

->  Index Scan using idx_parameter_value on parameter p
(cost=0.00..437.42 rows=23 width=13) (actual time=6.091..20.656 rows=663
loops=1)

Index Cond: (value = '099'::text)

Filter: (name = 'countyNo'::text)

->  Index Scan using idx_serviceinstanceparameter_fkparameterid on
serviceinstanceparameter sip  (cost=0.00..3.07 rows=1 width=8) (actual
time=0.278..0.288 rows=1 loops=663)

Index Cond: (sip.fkparameterid = "outer".parameterid)

->  Index Scan using pk_serviceinstance_serviceinstanceid on
serviceinstance si  (cost=0.00..5.40 rows=1 width=78) (actual
time=0.041..0.073 rows=1 loops=663)

Index Cond: (si.serviceinstanceid = "outer".fkserviceinstanceid)
                                                                     ->
Hash  (cost=2.38..2.38 rows=3 width=4) (actual time=0.445..0.445 rows=0
loops=1)

->  Hash Join  (cost=1.08..2.38 rows=3 width=4) (actual
time=0.314..0.426 rows=1 loops=1)

Hash Cond: ("outer".fkserviceid = "inner".serviceid)

->  Seq Scan on serviceoffering so  (cost=0.00..1.18 rows=18width=8)
(actual time=0.005..0.065 rows=18 loops=1)

->  Hash  (cost=1.07..1.07 rows=1 width=4) (actual time=0.033..0.033
rows=0 loops=1)

->  Seq Scan on service s  (cost=0.00..1.07 rows=1 width=4) (actual
time=0.011..0.016 rows=1 loops=1)

Filter: (servicename = 'alert'::text)
                                                               ->  Hash
(cost=1.06..1.06 rows=1 width=16) (actual time=0.031..0.031 rows=0 loops=1)
                                                                     ->
Seq Scan on serviceinstancestatus sis  (cost=0.00..1.06 rows=1 width=16)
(actual time=0.008..0.014 rows=1 loops=1)

Filter: (status = 'ACTIVE'::text)
                                                         ->  Hash Join
(cost=3.45..13386.23 rows=165 width=21) (actual time=0.119..461.891
rows=3935 loops=226)
                                                               Hash
Cond: ("outer".fkserviceinstancestatusid = "inner".serviceinstancestatusid)
                                                               ->  Hash
Join  (cost=2.38..13382.69 rows=165 width=25) (actual
time=0.110..432.555 rows=3935 loops=226)

Hash Cond: ("outer".fkserviceofferingid = "inner".serviceofferingid)
                                                                     ->
Nested Loop  (cost=0.00..13373.71 rows=990 width=29) (actual
time=0.098..400.805 rows=3935 loops=226)

->  Nested Loop  (cost=0.00..8015.16 rows=990 width=13) (actual
time=0.035..267.634 rows=3935 loops=226)

->  Seq Scan on parameter p  (cost=0.00..4968.81 rows=989 width=13)
(actual time=0.008..131.735 rows=3935 loops=226)

Filter: ((name = 'countyState'::text) AND (value = 'FL'::text))

->  Index Scan using idx_serviceinstanceparameter_fkparameterid on
serviceinstanceparameter sip  (cost=0.00..3.07 rows=1 width=8) (actual
time=0.015..0.020 rows=1 loops=889310)

Index Cond: (sip.fkparameterid = "outer".parameterid)

->  Index Scan using pk_serviceinstance_serviceinstanceid on
serviceinstance si  (cost=0.00..5.40 rows=1 width=16) (actual
time=0.012..0.019 rows=1 loops=889310)

Index Cond: (si.serviceinstanceid = "outer".fkserviceinstanceid)
                                                                     ->
Hash  (cost=2.38..2.38 rows=3 width=4) (actual time=0.439..0.439 rows=0
loops=1)

->  Hash Join  (cost=1.08..2.38 rows=3 width=4) (actual
time=0.310..0.423 rows=1 loops=1)

Hash Cond: ("outer".fkserviceid = "inner".serviceid)

->  Seq Scan on serviceoffering so  (cost=0.00..1.18 rows=18 width=8)
(actual time=0.006..0.065 rows=18 loops=1)

->  Hash  (cost=1.07..1.07 rows=1 width=4) (actual time=0.035..0.035
rows=0 loops=1)

->  Seq Scan on service s  (cost=0.00..1.07 rows=1 width=4) (actual
time=0.013..0.018 rows=1 loops=1)

Filter: (servicename = 'alert'::text)
                                                               ->  Hash
(cost=1.05..1.05 rows=5 width=4) (actual time=0.059..0.059 rows=0 loops=1)
                                                                     ->
Seq Scan on serviceinstancestatus sis  (cost=0.00..1.05 rows=5 width=4)
(actual time=0.010..0.029 rows=5 loops=1)
                                                   ->  Index Scan using
pk_serviceinstance_serviceinstanceid on serviceinstance si
(cost=0.00..5.40 rows=1 width=16) (actual time=0.009..0.012 rows=1
loops=110)
                                                         Index Cond:
(si.serviceinstanceid = "outer".fkserviceinstanceid)
                                             ->  Hash  (cost=1.05..1.05
rows=5 width=4) (actual time=0.055..0.055 rows=0 loops=1)
                                                   ->  Seq Scan on
serviceinstancestatus sis  (cost=0.00..1.05 rows=5 width=4) (actual
time=0.008..0.025 rows=5 loops=1)
                                       ->  Hash  (cost=2.38..2.38 rows=3
width=4) (actual time=0.461..0.461 rows=0 loops=1)
                                             ->  Hash Join
(cost=1.08..2.38 rows=3 width=4) (actual time=0.325..0.445 rows=1 loops=1)
                                                   Hash Cond:
("outer".fkserviceid = "inner".serviceid)
                                                   ->  Seq Scan on
serviceoffering so  (cost=0.00..1.18 rows=18 width=8) (actual
time=0.006..0.074 rows=18 loops=1)
                                                   ->  Hash
(cost=1.07..1.07 rows=1 width=4) (actual time=0.044..0.044 rows=0 loops=1)
                                                         ->  Seq Scan on
service s  (cost=0.00..1.07 rows=1 width=4) (actual time=0.022..0.027
rows=1 loops=1)
                                                               Filter:
(servicename = 'alert'::text)
                                 ->  Index Scan using
idx_serviceinstanceparameter_fkserviceinstanceid on
serviceinstanceparameter sip  (cost=0.00..3.41 rows=5 width=8) (actual
time=0.018..0.038 rows=5 loops=110)
                                       Index Cond:
(sip.fkserviceinstanceid = "outer".fkserviceinstanceid)
                           ->  Index Scan using pk_parameter_parameterid
on parameter p  (cost=0.00..3.02 rows=1 width=13) (actual
time=0.011..0.012 rows=0 loops=550)
                                 Index Cond: ("outer".fkparameterid =
p.parameterid)
                                 Filter: (name = 'listingType'::text)

 Total runtime: 113490.582 ms
(82 rows)



Tom Lane wrote:
>Pallav Kalva <pkalva@livedatagroup.com> writes:
>
>>   I am having problem optimizing this query,
>>
>
>Get rid of the un-optimizable function inside the view.  You've
>converted something that should be a join into an unreasonably large
>number of function calls.
>
>
>>                    ->  Seq Scan on serviceinstance si
>>(cost=0.00..15831.52 rows=7 width=78) (actual time=174.430..18948.210
>>rows=358 loops=1)
>>                          Filter: (((subplan) = 'FL'::text) AND
>>((subplan) = '099'::text))
>>                          SubPlan
>>                            ->  Result  (cost=0.00..0.01 rows=1 width=0)
>>(actual time=0.090..0.093 rows=1 loops=3923)
>>                            ->  Result  (cost=0.00..0.01 rows=1 width=0)
>>(actual time=0.058..0.061 rows=1 loops=265617)
>>
>
>The bulk of the cost here is in the second subplan (0.061 * 265617 =
>16202.637 msec total runtime), and there's not a darn thing Postgres
>can do to improve this because the work is all down inside a "black box"
>function.  In fact the planner does not even know that the function call
>is expensive, else it would have preferred a plan that requires fewer
>evaluations of the function.  The alternative plan you show is *not*
>faster "because it's an indexscan"; it's faster because get_parametervalue
>is evaluated fewer times.
>
>The useless sub-SELECTs atop the function calls are adding their own
>little increment of wasted time, too.  I'm not sure how bad that is
>relative to the function calls, but it's certainly not helping.
>
>            regards, tom lane
>
>


Re: Postgres8.0 planner chooses WRONG plan

From
"Jim C. Nasby"
Date:
On Wed, Jan 11, 2006 at 11:44:58AM -0500, Pallav Kalva wrote:
Some view you've got there... you might want to break that apart into
multiple views that are a bit easier to manage.
service_instance_with_status is a likely candidate, for example.

> View Definition
> -------------------
>
> create or replace view provisioning.alertserviceinstanceold as
> SELECT services.serviceinstanceid, a.accountid, c.firstname, c.lastname,
> c.email, services.countyno, services.countystate, services.listingtype
> AS listingtypename, services.status, services.affiliate,
> services.affiliatesub, services."domain"
>   FROM provisioning.account a
>   JOIN common.contact c ON a.fkcontactid = c.contactid
>   JOIN ( SELECT p1.serviceinstanceid, p1.accountid, p1.countyno,
> p2.countystate, p3.listingtype, p1.status, p1.affiliate,
> p1.affiliatesub, p1."domain"
>      FROM ( SELECT si.serviceinstanceid, si.affiliate, si.affiliatesub,
> si."domain", si.fkaccountid AS accountid, p.value AS countyno, sis.status
>              FROM provisioning.service s
>         JOIN provisioning.serviceoffering so ON s.serviceid =
> so.fkserviceid
>    JOIN provisioning.serviceinstance si ON so.serviceofferingid =
> si.fkserviceofferingid
>   JOIN provisioning.serviceinstancestatus sis ON
> si.fkserviceinstancestatusid = sis.serviceinstancestatusid
>   JOIN provisioning.serviceinstanceparameter sip ON
> si.serviceinstanceid = sip.fkserviceinstanceid
>   JOIN common.parameter p ON sip.fkparameterid = p.parameterid
>  WHERE s.servicename = 'alert'::text AND p.name = 'countyNo'::text) p1
>   JOIN ( SELECT si.serviceinstanceid, si.affiliate, si.affiliatesub,
> si."domain", si.fkaccountid AS accountid, p.value AS countystate, sis.status
>              FROM provisioning.service s
>         JOIN provisioning.serviceoffering so ON s.serviceid =
> so.fkserviceid
>    JOIN provisioning.serviceinstance si ON so.serviceofferingid =
> si.fkserviceofferingid
>   JOIN provisioning.serviceinstancestatus sis ON
> si.fkserviceinstancestatusid = sis.serviceinstancestatusid
>   JOIN provisioning.serviceinstanceparameter sip ON
> si.serviceinstanceid = sip.fkserviceinstanceid
>   JOIN common.parameter p ON sip.fkparameterid = p.parameterid
>  WHERE s.servicename = 'alert'::text AND p.name = 'countyState'::text)
> p2 ON p1.accountid = p2.accountid AND p1.serviceinstanceid =
> p2.serviceinstanceid
>   JOIN ( SELECT si.serviceinstanceid, si.affiliate, si.affiliatesub,
> si."domain", si.fkaccountid AS accountid, p.value AS listingtype, sis.status
>         FROM provisioning.service s
>    JOIN provisioning.serviceoffering so ON s.serviceid = so.fkserviceid
>   JOIN provisioning.serviceinstance si ON so.serviceofferingid =
> si.fkserviceofferingid
>   JOIN provisioning.serviceinstancestatus sis ON
> si.fkserviceinstancestatusid = sis.serviceinstancestatusid
>   JOIN provisioning.serviceinstanceparameter sip ON
> si.serviceinstanceid = sip.fkserviceinstanceid
>   JOIN common.parameter p ON sip.fkparameterid = p.parameterid
>  WHERE s.servicename = 'alert'::text AND p.name = 'listingType'::text)
> p3 ON p2.accountid = p3.accountid AND p2.serviceinstanceid =
> p3.serviceinstanceid) services
> ON a.accountid = services.accountid
> ORDER BY services.serviceinstanceid;
>
> Explain Analyze
> ------------------
> explain analyze
> select * from provisioning.alertserviceinstanceold where countystate =
> 'FL' and countyno = '099' and status = 'ACTIVE' ;
>
>
     
> QUERY PLAN
>
>
----------------------------------------------------------------------------------------------------------------------------------------------
> --------------------------------------------------------------------------------------------------------------------
> Subquery Scan alertserviceinstanceold  (cost=31954.24..31954.25 rows=1
> width=328) (actual time=113485.801..113487.024 rows=110 loops=1)
>   ->  Sort  (cost=31954.24..31954.24 rows=1 width=152) (actual
> time=113485.787..113486.123 rows=110 loops=1)
>         Sort Key: si.serviceinstanceid
>         ->  Hash Join  (cost=20636.38..31954.23 rows=1 width=152)
> (actual time=109721.688..113485.311 rows=110 loops=1)
>               Hash Cond: ("outer".accountid = "inner".fkaccountid)
>               ->  Hash Join  (cost=6595.89..16770.25 rows=228696
> width=47) (actual time=1742.592..4828.396 rows=229855 loops=1)
>                     Hash Cond: ("outer".contactid = "inner".fkcontactid)
>                     ->  Seq Scan on contact c  (cost=0.00..4456.96
> rows=228696 width=47) (actual time=0.006..1106.459 rows=229868 loops=1)
>                     ->  Hash  (cost=6024.11..6024.11 rows=228711
> width=8) (actual time=1742.373..1742.373 rows=0 loops=1)
>                           ->  Seq Scan on account a
> (cost=0.00..6024.11 rows=228711 width=8) (actual time=0.010..990.597
> rows=229855 loops=1)
>               ->  Hash  (cost=14040.49..14040.49 rows=1 width=117)
> (actual time=107911.397..107911.397 rows=0 loops=1)
>                     ->  Nested Loop  (cost=10.34..14040.49 rows=1
> width=117) (actual time=1185.383..107910.738 rows=110 loops=1)
>                           ->  Nested Loop  (cost=10.34..14037.45 rows=1
> width=112) (actual time=1185.278..107898.885 rows=550 loops=1)
>                                 ->  Hash Join  (cost=10.34..14033.98
> rows=1 width=124) (actual time=1185.224..107888.542 rows=110 loops=1)
>                                       Hash Cond:
> ("outer".fkserviceofferingid = "inner".serviceofferingid)
>                                       ->  Hash Join
> (cost=7.96..14031.58 rows=1 width=128) (actual time=1184.490..107886.329
> rows=110 loops=1)
>                                             Hash Cond:
> ("outer".fkserviceinstancestatusid = "inner".serviceinstancestatusid)
>                                             ->  Nested Loop
> (cost=6.90..14030.50 rows=1 width=132) (actual time=1184.151..107884.302
> rows=110 loops=1)
>                                                   Join Filter:
> ("outer".fkaccountid = "inner".fkaccountid)

Well, here's the step that's killing you:
>                                                   ->  Nested Loop
> (cost=6.90..14025.09 rows=1 width=116) (actual time=1184.123..107880.635
> rows=110 loops=1)
>                                                         Join Filter:
> (("outer".fkaccountid = "inner".fkaccountid) AND
> ("outer".serviceinstanceid = "inner".serviceinstanceid))
>                                                         ->  Hash Join
> (cost=3.45..636.39 rows=1 width=95) (actual time=85.524..293.387
> rows=226 loops=1)
>                                                               Hash
> Cond: ("outer".fkserviceinstancestatusid = "inner".serviceinstancestatusid)

Unfortunately, the way this query plan came out it's difficult to figure
out what the other input to that nested loop is. But before we get to
that, what do you have join_collapse_limit set to? If it's the default
of 8 then the optimizer is essentially going to follow the join order
you specified when you wrote the view, which could be far from optimal.
It would be worth setting join_collapse_limit high enough so that this
query will get flattened and see what kind of plan it comes up with
then. Note that this could result in an unreasonably-large plan time,
but if it results in a fast query execution we know it's just a matter
of re-ordering things in the query.

Also, it would be best if you could send the results of explain as an
attachement that hasn't been word-wrapped.

>                                                               ->  Hash
> Join  (cost=2.38..635.29 rows=4 width=87) (actual time=6.894..289.000
> rows=663 loops=1)
>
> Hash Cond: ("outer".fkserviceofferingid = "inner".serviceofferingid)
>                                                                     ->
> Nested Loop  (cost=0.00..632.75 rows=23 width=91) (actual
> time=6.176..281.620 rows=663 loops=1)
>
> ->  Nested Loop  (cost=0.00..508.26 rows=23 width=13) (actual
> time=6.138..221.590 rows=663 loops=1)
>
> ->  Index Scan using idx_parameter_value on parameter p
> (cost=0.00..437.42 rows=23 width=13) (actual time=6.091..20.656 rows=663
> loops=1)
>
> Index Cond: (value = '099'::text)
>
> Filter: (name = 'countyNo'::text)
>
> ->  Index Scan using idx_serviceinstanceparameter_fkparameterid on
> serviceinstanceparameter sip  (cost=0.00..3.07 rows=1 width=8) (actual
> time=0.278..0.288 rows=1 loops=663)
>
> Index Cond: (sip.fkparameterid = "outer".parameterid)
>
> ->  Index Scan using pk_serviceinstance_serviceinstanceid on
> serviceinstance si  (cost=0.00..5.40 rows=1 width=78) (actual
> time=0.041..0.073 rows=1 loops=663)
>
> Index Cond: (si.serviceinstanceid = "outer".fkserviceinstanceid)
>                                                                     ->
> Hash  (cost=2.38..2.38 rows=3 width=4) (actual time=0.445..0.445 rows=0
> loops=1)
>
> ->  Hash Join  (cost=1.08..2.38 rows=3 width=4) (actual
> time=0.314..0.426 rows=1 loops=1)
>
> Hash Cond: ("outer".fkserviceid = "inner".serviceid)
>
> ->  Seq Scan on serviceoffering so  (cost=0.00..1.18 rows=18width=8)
> (actual time=0.005..0.065 rows=18 loops=1)
>
> ->  Hash  (cost=1.07..1.07 rows=1 width=4) (actual time=0.033..0.033
> rows=0 loops=1)
>
> ->  Seq Scan on service s  (cost=0.00..1.07 rows=1 width=4) (actual
> time=0.011..0.016 rows=1 loops=1)
>
> Filter: (servicename = 'alert'::text)
>                                                               ->  Hash
> (cost=1.06..1.06 rows=1 width=16) (actual time=0.031..0.031 rows=0 loops=1)
>                                                                     ->
> Seq Scan on serviceinstancestatus sis  (cost=0.00..1.06 rows=1 width=16)
> (actual time=0.008..0.014 rows=1 loops=1)
>
> Filter: (status = 'ACTIVE'::text)
>                                                         ->  Hash Join
> (cost=3.45..13386.23 rows=165 width=21) (actual time=0.119..461.891
> rows=3935 loops=226)
>                                                               Hash
> Cond: ("outer".fkserviceinstancestatusid = "inner".serviceinstancestatusid)
>                                                               ->  Hash
> Join  (cost=2.38..13382.69 rows=165 width=25) (actual
> time=0.110..432.555 rows=3935 loops=226)
>
> Hash Cond: ("outer".fkserviceofferingid = "inner".serviceofferingid)
>                                                                     ->
> Nested Loop  (cost=0.00..13373.71 rows=990 width=29) (actual
> time=0.098..400.805 rows=3935 loops=226)
>
> ->  Nested Loop  (cost=0.00..8015.16 rows=990 width=13) (actual
> time=0.035..267.634 rows=3935 loops=226)
>
> ->  Seq Scan on parameter p  (cost=0.00..4968.81 rows=989 width=13)
> (actual time=0.008..131.735 rows=3935 loops=226)
>
> Filter: ((name = 'countyState'::text) AND (value = 'FL'::text))
>
> ->  Index Scan using idx_serviceinstanceparameter_fkparameterid on
> serviceinstanceparameter sip  (cost=0.00..3.07 rows=1 width=8) (actual
> time=0.015..0.020 rows=1 loops=889310)
>
> Index Cond: (sip.fkparameterid = "outer".parameterid)
>
> ->  Index Scan using pk_serviceinstance_serviceinstanceid on
> serviceinstance si  (cost=0.00..5.40 rows=1 width=16) (actual
> time=0.012..0.019 rows=1 loops=889310)
>
> Index Cond: (si.serviceinstanceid = "outer".fkserviceinstanceid)
>                                                                     ->
> Hash  (cost=2.38..2.38 rows=3 width=4) (actual time=0.439..0.439 rows=0
> loops=1)
>
> ->  Hash Join  (cost=1.08..2.38 rows=3 width=4) (actual
> time=0.310..0.423 rows=1 loops=1)
>
> Hash Cond: ("outer".fkserviceid = "inner".serviceid)
>
> ->  Seq Scan on serviceoffering so  (cost=0.00..1.18 rows=18 width=8)
> (actual time=0.006..0.065 rows=18 loops=1)
>
> ->  Hash  (cost=1.07..1.07 rows=1 width=4) (actual time=0.035..0.035
> rows=0 loops=1)
>
> ->  Seq Scan on service s  (cost=0.00..1.07 rows=1 width=4) (actual
> time=0.013..0.018 rows=1 loops=1)
>
> Filter: (servicename = 'alert'::text)
>                                                               ->  Hash
> (cost=1.05..1.05 rows=5 width=4) (actual time=0.059..0.059 rows=0 loops=1)
>                                                                     ->
> Seq Scan on serviceinstancestatus sis  (cost=0.00..1.05 rows=5 width=4)
> (actual time=0.010..0.029 rows=5 loops=1)
>                                                   ->  Index Scan using
> pk_serviceinstance_serviceinstanceid on serviceinstance si
> (cost=0.00..5.40 rows=1 width=16) (actual time=0.009..0.012 rows=1
> loops=110)
>                                                         Index Cond:
> (si.serviceinstanceid = "outer".fkserviceinstanceid)
>                                             ->  Hash  (cost=1.05..1.05
> rows=5 width=4) (actual time=0.055..0.055 rows=0 loops=1)
>                                                   ->  Seq Scan on
> serviceinstancestatus sis  (cost=0.00..1.05 rows=5 width=4) (actual
> time=0.008..0.025 rows=5 loops=1)
>                                       ->  Hash  (cost=2.38..2.38 rows=3
> width=4) (actual time=0.461..0.461 rows=0 loops=1)
>                                             ->  Hash Join
> (cost=1.08..2.38 rows=3 width=4) (actual time=0.325..0.445 rows=1 loops=1)
>                                                   Hash Cond:
> ("outer".fkserviceid = "inner".serviceid)
>                                                   ->  Seq Scan on
> serviceoffering so  (cost=0.00..1.18 rows=18 width=8) (actual
> time=0.006..0.074 rows=18 loops=1)
>                                                   ->  Hash
> (cost=1.07..1.07 rows=1 width=4) (actual time=0.044..0.044 rows=0 loops=1)
>                                                         ->  Seq Scan on
> service s  (cost=0.00..1.07 rows=1 width=4) (actual time=0.022..0.027
> rows=1 loops=1)
>                                                               Filter:
> (servicename = 'alert'::text)
>                                 ->  Index Scan using
> idx_serviceinstanceparameter_fkserviceinstanceid on
> serviceinstanceparameter sip  (cost=0.00..3.41 rows=5 width=8) (actual
> time=0.018..0.038 rows=5 loops=110)
>                                       Index Cond:
> (sip.fkserviceinstanceid = "outer".fkserviceinstanceid)
>                           ->  Index Scan using pk_parameter_parameterid
> on parameter p  (cost=0.00..3.02 rows=1 width=13) (actual
> time=0.011..0.012 rows=0 loops=550)
>                                 Index Cond: ("outer".fkparameterid =
> p.parameterid)
>                                 Filter: (name = 'listingType'::text)
>
> Total runtime: 113490.582 ms
> (82 rows)
--
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