Changing to High priority because it relates pretty directly to patrons and it has to do with money. Both very important and potentially painful things. That said, trying the correct view resulted in terrible performance on our 9.1 database: Here's the incorrect, original view: EXPLAIN ANALYZE SELECT * FROM money.transaction_billing_summary WHERE xact = 1055743; QUERY PLAN -------------------------------------------------------------------------------------------------------------------------------------- Sort (cost=27.31..27.32 rows=1 width=72) (actual time=0.427..0.427 rows=1 loops=1) Sort Key: (max(billing.billing_ts)) Sort Method: quicksort Memory: 25kB -> GroupAggregate (cost=0.00..27.30 rows=1 width=72) (actual time=0.412..0.412 rows=1 loops=1) -> Index Scan using m_b_xact_idx on billing (cost=0.00..17.65 rows=19 width=72) (actual time=0.059..0.145 rows=32 loops=1) Index Cond: (xact = 1055743) Filter: (voided IS FALSE) Total runtime: 0.514 ms (8 rows) Here's the correct, windowed view: EXPLAIN ANALYZE SELECT * FROM money.transaction_billing_summary WHERE xact = 1055743; QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------------------- Subquery Scan on transaction_billing_summary (cost=389206.01..397046.79 rows=1742 width=112) (actual time=16954.467..17031.868 rows=1 loops=1) Filter: (transaction_billing_summary.xact = 1055743) -> HashAggregate (cost=389206.01..392690.80 rows=348479 width=72) (actual time=16930.022..17007.854 rows=135940 loops=1) -> WindowAgg (cost=302984.69..362261.85 rows=2155533 width=72) (actual time=8766.521..14677.489 rows=2161543 loops=1) -> Sort (cost=302984.69..308373.53 rows=2155533 width=72) (actual time=8766.454..10138.737 rows=2161543 loops=1) Sort Key: billing.xact, billing.billing_ts Sort Method: external merge Disk: 170368kB -> Seq Scan on billing (cost=0.00..76226.79 rows=2155533 width=72) (actual time=0.014..1353.749 rows=2161543 loops=1) Filter: (voided IS FALSE) Total runtime: 17091.181 ms (10 rows) After creating an index such as CREATE INDEX CONCURRENTLY m_b_xact_time_idx ON money.billing (xact, billing_ts);, that drops to the following: EXPLAIN ANALYZE SELECT * FROM money.transaction_billing_summary WHERE xact = 1055743; QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------------------------------------ Subquery Scan on transaction_billing_summary (cost=234806.53..242647.30 rows=1742 width=112) (actual time=8516.624..8587.789 rows=1 loops=1) Filter: (transaction_billing_summary.xact = 1055743) -> HashAggregate (cost=234806.53..238291.32 rows=348479 width=72) (actual time=8495.631..8564.848 rows=135940 loops=1) -> WindowAgg (cost=0.00..207862.36 rows=2155533 width=72) (actual time=0.104..6328.666 rows=2161543 loops=1) -> Index Scan using m_b_xact_time_idx on billing (cost=0.00..153974.04 rows=2155533 width=72) (actual time=0.059..1745.327 rows=2161543 loops=1) Total runtime: 8592.926 ms (6 rows) Maybe we have an unusually large billing table? SELECT COUNT(*) FROM money.billing; count --------- 2681879 (1 row) ... but going from 0.5ms to 8600ms is a huge performance hit that we're going to want to watch carefully. (Yes, the explain analyze statements were repeated to ensure that as much data was cached as possible).