Received: from maia.hub.org (unknown [200.46.204.183]) by mail.postgresql.org (Postfix) with ESMTP id 05E1F63275D for ; Fri, 30 Oct 2009 05:40:48 -0300 (ADT) Received: from mail.postgresql.org ([200.46.204.86]) by maia.hub.org (mx1.hub.org [200.46.204.183]) (amavisd-maia, port 10024) with ESMTP id 85854-04 for ; Fri, 30 Oct 2009 08:40:40 +0000 (UTC) X-Greylist: from auto-whitelisted by SQLgrey-1.7.6 Received: from relay.ptn-ipout01.plus.net (relay.ptn-ipout01.plus.net [212.159.7.35]) by mail.postgresql.org (Postfix) with ESMTP id 0D71263235C for ; Fri, 30 Oct 2009 05:40:39 -0300 (ADT) X-IronPort-Anti-Spam-Filtered: true X-IronPort-Anti-Spam-Result: ApoEAMxC6krUnw4T/2dsb2JhbADgb4Q9BIFi Received: from pih-relay06.plus.net ([212.159.14.19]) by relay.ptn-ipout01.plus.net with ESMTP; 30 Oct 2009 08:40:37 +0000 Received: from [84.51.143.99] (helo=server3.office.archonet.com) by pih-relay06.plus.net with esmtp (Exim) id 1N3n2D-0007Bt-Gg; Fri, 30 Oct 2009 08:40:37 +0000 Received: from [192.168.1.36] (dell36.office.archonet.com [192.168.1.36]) by server3.office.archonet.com (Postfix) with ESMTPA id 11E0927405D; Fri, 30 Oct 2009 08:40:37 +0000 (GMT) Message-ID: <4AEAA684.60905@archonet.com> Date: Fri, 30 Oct 2009 08:40:36 +0000 From: Richard Huxton User-Agent: Thunderbird 2.0.0.23 (X11/20090817) MIME-Version: 1.0 To: Grant Masan CC: pgsql-sql@postgresql.org Subject: Re: slow count(CASE) query References: In-Reply-To: Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: 7bit X-Plusnet-Relay: dd26b13d42b1a70d0f5987b18db83a8e X-Virus-Scanned: Maia Mailguard 1.0.1 X-Spam-Status: No, hits=-1.185 tagged_above=-10 required=5 tests=BAYES_40=-0.185, RCVD_IN_DNSWL_LOW=-1 X-Spam-Level: X-Archive-Number: 200910/144 X-Sequence-Number: 33343 Grant Masan wrote: > > select '000100' as length, sum(ship1) as ship1 ,sum(ship2) as > ship2,sum(ship3) as ship3,sum(ship4) as ship4,sum(ship5) as ship5 FROM > (select > count(CASE WHEN (type between 40 and 49) THEN 1 ELSE NULL END) as ship1, > count(CASE WHEN (type between 60 and 69) THEN 1 ELSE NULL END) as ship2, > count(CASE WHEN (type between 70 and 79) THEN 1 ELSE NULL END) as ship3, > count(CASE WHEN (type between 80 and 89) THEN 1 ELSE NULL END) as ship4, > count(CASE WHEN (type >90) THEN 1 ELSE NULL END) as ship5 > FROM school_proj_boat where length <100 > GROUP BY type > ORDER BY type) as koo > > UNION ALL > > select '100200' as length, sum(ship1) as ship1 ,sum(ship2) as ... > FROM school_proj_boat where length between 100 and 200 > GROUP BY type > ORDER BY type) as koo > > UNION ALL ... First thing is to ditch the UNION ALLs. You're basically repeating the same query. Create a lookup table: length_codes (code, min_length, max_length) Data: ('100100', 0, 99), ('100200', 100, 199), ... SELECT length_code AS length, sum... FROM ( SELECT lc.code AS length_code, count(case)... FROM school_proj_boat spb, length_codes lc WHERE spb.length BETWEEN lc.min_length AND lc.max_length ) AS koo ; It's easy to forget that you can join against a table using any condition, it doesn't have to be equality. Here we use BETWEEN to replace our UNIONs. You'll want a unique constraint on length_codes.code and you should really write a custom trigger to make sure none of the min_length..max_length ranges overlap. In practice, you're probably only setting this table up once so might not bother. -- Richard Huxton Archonet Ltd