The nested view from hell - Restricting a subquerry - Mailing list pgsql-sql

From Bryce Nesbitt
Subject The nested view from hell - Restricting a subquerry
Date
Msg-id 46A2CABF.3080108@obviously.com
Whole thread Raw
Responses Re: The nested view from hell - Restricting a subquerry  (Nis Jørgensen <nis@superlativ.dk>)
List pgsql-sql
I've got a legacy app with a hefty performance problem.  The basic problem is stupid design. It takes 10-15 seconds of
CPUtime to look up an invoice.<br /> Basically it's trying to mash up extra columns on an otherwise simple query, and
thoseextra columns are subtotals.  Simplified (this looks best in a fixed width font):<br /><br /><tt>    SELECT 
max(order_view.order_id),max(order_view.invoice_id),sum(order_view.mileage)<br />     FROM    (SELECT
order_id,invoice_id,0 as miles FROM eg_order<br />              UNION    <br />              SELECT order_id,0        
,     miles FROM eg_order_line)<br />              order_view GROUP BY order_view.order_id;<br /></tt><br /> A select
byorder_id is fast.  The problem is the application uses "select * from view where invoice_id=x", and the second part
ofthe UNION returns all possible rows in the database.  These get filtered out later, but at considerable performance
hit.<br/><br /> Is there a way to get the "where invoice_id=x" into the subquery?  "select distinct order_id from
eg_orderwhere invoice_id=x" would do it.<br /> I can't redesign the view, because it all goes into an object relational
mapperthat thinks it's a real table.<br /><br />                    -Bryce Nesbitt<br /><br /><br /><tt>stage=# \d
eg_invoice_summary_view<br/>         View "public.eg_invoice_summary_view"<br />      Column     |         
Type         | Modifiers <br /> ----------------+------------------------+-----------<br />  invoice_id     |
integer               | <br />  cso_id         | integer                | <br />  period_id      |
integer               | <br />  account_id     | integer                | <br />  invoice_number | character
varying(192)| <br />  invoice_date   | date                   | <br />  amount         | numeric                | <br
/> tax            | bigint                 | <br />  invoice_style  | integer                | <br />  plan_name      |
charactervarying(128) | <br /> View definition:<br />  SELECT i.invoice_id, i.cso_id, i.period_id, i.account_id,
i.invoice_number,i.invoice_date, i.amount, sum(tax.tax_amount) AS tax, i.invoice_style, i.plan_name<br />    FROM (
SELECTi.invoice_id, i.cso_id, i.period_id, i.account_id, i.invoice_number, i.invoice_date, sum(o.amount) AS amount,
i.invoice_style,i.plan_name<br />            FROM eg_invoice i<br />       LEFT JOIN <b>eg_order_summary_view</b> o ON
i.invoice_id= o.invoice_id<br />      GROUP BY i.invoice_id, i.cso_id, i.period_id, i.account_id, i.invoice_number,
i.invoice_date,i.invoice_style, i.plan_name) i<br />    LEFT JOIN eg_invoice_tax tax ON i.invoice_id =
tax.invoice_id<br/>   GROUP BY i.invoice_id, i.cso_id, i.period_id, i.account_id, i.invoice_number, i.invoice_date,
i.amount,i.invoice_style, i.plan_name;<br /><br /> stage=# \d eg_order_summary_view<br />         View
"public.eg_order_summary_view"<br/>    Column   |           Type           | Modifiers <br />
------------+--------------------------+-----------<br/>  order_id   | integer                  | <br />  d          |
"unknown"               | <br />  cso_id     | integer                  | <br />  invoice_id | integer                 
|<br />  period_id  | integer                  | <br />  ref_id     | integer                  | <br />  order_type |
integer                 | <br />  desc1      | text                     | <br />  desc2      | text                    
|<br />  desc3      | text                     | <br />  desc4      | text                     | <br />  desc5      |
text                    | <br />  desc6      | text                     | <br />  desc7      | text                    
|<br />  desc8      | text                     | <br />  order_from | timestamp with time zone | <br />  order_to   |
timestampwith time zone | <br />  hours      | double precision         | <br />  mileage    | double precision        
|<br />  amount     | bigint                   | <br /> View definition:<br />  SELECT <b>order_view.order_id</b>, 'D'
ASd, max(order_view.cso_id) AS cso_id, <b>max(order_view.invoice_id) AS invoice_id</b>, max(order_view.period_id) AS
period_id,max(order_view.ref_id) AS ref_id, max(order_view.order_type) AS order_type, max(order_view.desc1::text) AS
desc1,max(order_view.desc2::text) AS desc2, max(order_view.desc3::text) AS desc3, max(order_view.desc4::text) AS desc4,
max(order_view.desc5::text)AS desc5, max(order_view.desc6::text) AS desc6, max(order_view.desc7::text) AS desc7,
max(order_view.desc8::text)AS desc8, max(order_view.order_from) AS order_from, max(order_view.order_to) AS order_to,
sum(order_view.hours)AS hours, sum(order_view.mileage) AS mileage, sum(order_view.amount) AS amount<br />    FROM (
SELECTeg_order.order_id, eg_order.cso_id, e<b>g_order.invoice_id</b>, eg_order.period_id, eg_order.ref_id,
eg_order.order_type,eg_order.desc1, eg_order.desc2, eg_order.desc3, eg_order.desc4, eg_order.desc5, eg_order.desc6,
eg_order.desc7,eg_order.desc8, eg_order.order_from, eg_order.order_to, 0 AS hours, 0 AS mileage, 0 AS amount<br />
          FROM eg_order<br /> UNION <br />         ( SELECT <b>eg_order_line.order_id</b>, 0, <b>0</b>, 0, 0, 0,
NULL::"unknown"AS "unknown", NULL::"unknown" AS "unknown", NULL::"unknown" AS "unknown", NULL::"unknown" AS "unknown",
NULL::"unknown"AS "unknown", NULL::"unknown" AS "unknown", NULL::"unknown" AS "unknown", NULL::"unknown" AS "unknown",
to_timestamp('1970-01-01'::text,'YYYY-MM-DD'::text) AS to_timestamp, to_timestamp('1970-01-01'::text,
'YYYY-MM-DD'::text)AS to_timestamp, 0 AS hours, eg_order_line.quantity AS mileage, eg_order_line.amt_value<br />
          FROM eg_order_line<br />           WHERE eg_order_line.order_line_type = 20<br /> UNION <br />         
SELECT<b>eg_order_line.order_id</b>, 0, <b>0,</b> 0, 0, 0, NULL::"unknown" AS "unknown", NULL::"unknown" AS "unknown",
NULL::"unknown"AS "unknown", NULL::"unknown" AS "unknown", NULL::"unknown" AS "unknown", NULL::"unknown" AS "unknown",
NULL::"unknown"AS "unknown", NULL::"unknown" AS "unknown", to_timestamp('1970-01-01'::text, 'YYYY-MM-DD'::text) AS
to_timestamp,to_timestamp('1970-01-01'::text, 'YYYY-MM-DD'::text) AS to_timestamp, eg_order_line.quantity AS hours, 0
ASmileage, eg_order_line.amt_value<br />            FROM eg_order_line<br />           WHERE
eg_order_line.order_line_type<> 20)) order_view<br />   <b>GROUP BY order_view.order_id</b>;<br /><br /> stage=#
explainselect * from eg_invoice_summary_view where invoice_id=5;<br />
                                                                                                              <br />
   QUERY PLAN                                                                                                 <br />
                  <br />
---------------------------------------------------------------------------------------------------------------<br/>
---------------------------------------------------------------------------------------------------------------<br/>
-------------------<br/>  GroupAggregate  <b>(cost=485551.60..485551.80 rows=1 width=736)</b><br />    ->  Sort 
(cost=485551.60..485551.61rows=7 width=736)<br />          Sort Key: i.invoice_id, i.cso_id, i.period_id, i.account_id,
i.invoice_number,i.invoice_date, i.amoun<br /> t, i.invoice_style, i.plan_name<br />          ->  Nested Loop Left
Join (cost=485541.78..485551.50 rows=7 width=736)<br />                ->  HashAggregate  (cost=485540.75..485540.77
rows=1width=56)<br />                      ->  Nested Loop Left Join  (cost=417895.29..485536.25 rows=200
width=56)<br/>                            ->  Index Scan using eg_invoice_pkey on eg_invoice i  (cost=0.00..3.01
rows=1width=<br /> 48)<br />                                  Index Cond: (invoice_id = 5)<br />
                          ->  GroupAggregate  (cost=417895.29..485529.24 rows=200 width=316)<br />
                                Filter: (max("?column3?") = 5)<br />                                  ->  Unique 
(cost=417895.29..448632.54rows=614745 width=200)<br />                                        ->  Sort 
(cost=417895.29..419432.15rows=614745 width=200)<br />                                              Sort Key: order_id,
cso_id,invoice_id, period_id, ref_id, order_t<br /> ype, desc1, desc2, desc3, desc4, desc5, desc6, desc7, desc8,
order_from,order_to, hours, mileage, amount<br />                                              ->  Append 
(cost=0.00..106638.70rows=614745 width=200)<br />                                                    ->  Subquery
Scan"*SELECT* 1"  (cost=0.00..9621.64 rows=233<br /> 432 width=200)<br />
                                                        ->  Seq Scan on eg_order  (cost=0.00..7287.32 rows=233<br />
432width=200)<br />                                                    ->  Result  (cost=77951.41..97017.06
rows=381313width=16)<br />                                                          ->  Unique 
(cost=77951.41..97017.06rows=381313 width<br /> =16)<br />
                                                              ->  Sort  (cost=77951.41..78904.69 rows=381313 w<br />
idth=16)<br/>                                                                      Sort Key: order_id, cso_id,
invoice_id,pe<br /> riod_id, ref_id, order_type, desc1, desc2, desc3, desc4, desc5, desc6, desc7, desc8, order_from,
order_to,hour<br /> s, mileage, amount<br />                                                                     
-> Append  (cost=0.00..25112.52 rows=3813<br /> 13 width=16)<br />
                                                                          ->  Subquery Scan "*SELECT* 2"  (cos<br />
t=0.00..11887.06rows=146043 width=16)<br />
                                                                                ->  Seq Scan on eg_order_line <br />
 (cost=0.00..10426.63rows=146043 width=16)<br />
                                                                                      Filter: (order_line_type<br />  =
20)<br/>                                                                            ->  Subquery Scan "*SELECT* 3" 
(cos<br/> t=0.00..13225.46 rows=235270 width=16)<br />
                                                                                ->  Seq Scan on eg_order_line <br />
 (cost=0.00..10872.76rows=235270 width=16)<br />
                                                                                      Filter: (order_line_type<br />
 <>20)<br />                ->  Bitmap Heap Scan on eg_invoice_tax tax  (cost=1.03..10.65 rows=7 width=8)<br
/>                     Recheck Cond: (invoice_id = 5)<br />                      ->  Bitmap Index Scan on
ix2f10773c8edf278d (cost=0.00..1.03 rows=7 width=0)<br />                            Index Cond: (invoice_id = 5)<br />
(31rows)<br /><br /></tt><br /><br /><pre class="moz-signature" cols="100">-- 
 
----
Visit <a class="moz-txt-link-freetext" href="http://www.obviously.com/">http://www.obviously.com/</a>
</pre>

pgsql-sql by date:

Previous
From: ljb
Date:
Subject: Re: UNION and LIMIT issue
Next
From: Nis Jørgensen
Date:
Subject: Re: The nested view from hell - Restricting a subquerry