I've got a legacy app with a hefty performance problem. The basic problem is stupid design. It takes 10-15 seconds of CPU time to look up an invoice. Basically it's trying to mash up extra columns on an otherwise simple query, and those extra columns are subtotals. Simplified (this looks best in a fixed width font):
SELECT max(order_view.order_id),max(order_view.invoice_id) ,sum(order_view.mileage) FROM (SELECT order_id,invoice_id, 0 as miles FROM eg_order UNION SELECT order_id,0 , miles FROM eg_order_line) order_view GROUP BY order_view.order_id; A select by order_id is fast. The problem is the application uses "select * from view where invoice_id=x", and the second part of the UNION returns all possible rows in the database. These get filtered out later, but at considerable performance hit. Is there a way to get the "where invoice_id=x" into the subquery? "select distinct order_id from eg_order where invoice_id=x" would do it. I can't redesign the view, because it all goes into an object relational mapper that thinks it's a real table. -Bryce Nesbitt stage=# \d eg_invoice_summary_view View "public.eg_invoice_summary_view" Column | Type | Modifiers ----------------+------------------------+----------- invoice_id | integer | cso_id | integer | period_id | integer | account_id | integer | invoice_number | character varying(192) | invoice_date | date | amount | numeric | tax | bigint | invoice_style | integer | plan_name | character varying(128) | View definition: 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 FROM ( SELECT i.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 FROM eg_invoice i LEFT JOIN *eg_order_summary_view* o ON i.invoice_id = o.invoice_id 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 LEFT JOIN eg_invoice_tax tax ON i.invoice_id = tax.invoice_id 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; stage=# \d eg_order_summary_view View "public.eg_order_summary_view" Column | Type | Modifiers ------------+--------------------------+----------- order_id | integer | d | "unknown" | cso_id | integer | invoice_id | integer | period_id | integer | ref_id | integer | order_type | integer | desc1 | text | desc2 | text | desc3 | text | desc4 | text | desc5 | text | desc6 | text | desc7 | text | desc8 | text | order_from | timestamp with time zone | order_to | timestamp with time zone | hours | double precision | mileage | double precision | amount | bigint | View definition: SELECT *order_view.order_id*, 'D' AS d, max(order_view.cso_id) AS cso_id, *max(order_view.invoice_id) AS invoice_id*, 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 FROM ( SELECT eg_order.order_id, eg_order.cso_id, e*g_order.invoice_id*, 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 FROM eg_order UNION ( SELECT *eg_order_line.order_id*, 0, *0*, 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 FROM eg_order_line WHERE eg_order_line.order_line_type = 20 UNION SELECT *eg_order_line.order_id*, 0, *0,* 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 AS mileage, eg_order_line.amt_value FROM eg_order_line WHERE eg_order_line.order_line_type <> 20)) order_view *GROUP BY order_view.order_id*; stage=# explain select * from eg_invoice_summary_view where invoice_id=5; QUERY PLAN --------------------------------------------------------------------------------------------------------------- --------------------------------------------------------------------------------------------------------------- ------------------- GroupAggregate *(cost=485551.60..485551.80 rows=1 width=736)* -> Sort (cost=485551.60..485551.61 rows=7 width=736) Sort Key: i.invoice_id, i.cso_id, i.period_id, i.account_id, i.invoice_number, i.invoice_date, i.amoun t, i.invoice_style, i.plan_name -> Nested Loop Left Join (cost=485541.78..485551.50 rows=7 width=736) -> HashAggregate (cost=485540.75..485540.77 rows=1 width=56) -> Nested Loop Left Join (cost=417895.29..485536.25 rows=200 width=56) -> Index Scan using eg_invoice_pkey on eg_invoice i (cost=0.00..3.01 rows=1 width= 48) Index Cond: (invoice_id = 5) -> GroupAggregate (cost=417895.29..485529.24 rows=200 width=316) Filter: (max("?column3?") = 5) -> Unique (cost=417895.29..448632.54 rows=614745 width=200) -> Sort (cost=417895.29..419432.15 rows=614745 width=200) Sort Key: order_id, cso_id, invoice_id, period_id, ref_id, order_t ype, desc1, desc2, desc3, desc4, desc5, desc6, desc7, desc8, order_from, order_to, hours, mileage, amount -> Append (cost=0.00..106638.70 rows=614745 width=200) -> Subquery Scan "*SELECT* 1" (cost=0.00..9621.64 rows=233 432 width=200) -> Seq Scan on eg_order (cost=0.00..7287.32 rows=233 432 width=200) -> Result (cost=77951.41..97017.06 rows=381313 width=16) -> Unique (cost=77951.41..97017.06 rows=381313 width =16) -> Sort (cost=77951.41..78904.69 rows=381313 w idth=16) Sort Key: order_id, cso_id, invoice_id, pe riod_id, ref_id, order_type, desc1, desc2, desc3, desc4, desc5, desc6, desc7, desc8, order_from, order_to, hour s, mileage, amount -> Append (cost=0.00..25112.52 rows=3813 13 width=16) -> Subquery Scan "*SELECT* 2" (cos t=0.00..11887.06 rows=146043 width=16) -> Seq Scan on eg_order_line (cost=0.00..10426.63 rows=146043 width=16) Filter: (order_line_type = 20) -> Subquery Scan "*SELECT* 3" (cos t=0.00..13225.46 rows=235270 width=16) -> Seq Scan on eg_order_line (cost=0.00..10872.76 rows=235270 width=16) Filter: (order_line_type <> 20) -> Bitmap Heap Scan on eg_invoice_tax tax (cost=1.03..10.65 rows=7 width=8) Recheck Cond: (invoice_id = 5) -> Bitmap Index Scan on ix2f10773c8edf278d (cost=0.00..1.03 rows=7 width=0) Index Cond: (invoice_id = 5) (31 rows) -- ---- Visit http://www.obviously.com/