Received: from maia.hub.org (maia-3.hub.org [200.46.204.243]) by mail.postgresql.org (Postfix) with ESMTP id 9D8AEB5DBCC for ; Tue, 5 Jul 2011 07:15:53 -0300 (ADT) Received: from mail.postgresql.org ([200.46.204.86]) by maia.hub.org (mx1.hub.org [200.46.204.243]) (amavisd-maia, port 10024) with ESMTP id 29884-06 for ; Tue, 5 Jul 2011 10:15:47 +0000 (UTC) X-Greylist: from auto-whitelisted by SQLgrey-1.7.6 Received: from mail-wy0-f174.google.com (mail-wy0-f174.google.com [74.125.82.174]) by mail.postgresql.org (Postfix) with ESMTP id EF0BDB5DBCB for ; Tue, 5 Jul 2011 07:15:46 -0300 (ADT) Received: by wyg8 with SMTP id 8so3878838wyg.19 for ; Tue, 05 Jul 2011 03:15:45 -0700 (PDT) Received: by 10.227.12.20 with SMTP id v20mr6315960wbv.42.1309860945848; Tue, 05 Jul 2011 03:15:45 -0700 (PDT) Received: from mptpmbp.local (78-245.77-83.cust.bluewin.ch [83.77.245.78]) by mx.google.com with ESMTPS id ex2sm5179575wbb.14.2011.07.05.03.15.41 (version=SSLv3 cipher=OTHER); Tue, 05 Jul 2011 03:15:43 -0700 (PDT) Message-ID: <4E12E442.9020202@engene.se> Date: Tue, 05 Jul 2011 12:15:30 +0200 From: Marcus Engene User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.6; en-US; rv:1.9.1.16) Gecko/20101125 Thunderbird/3.0.11 MIME-Version: 1.0 To: pgsql-performance@postgresql.org Subject: Re: bitmask index References: <4E025E54.6020402@engene.se> <4E0261C1.8000807@2ndQuadrant.com> In-Reply-To: <4E0261C1.8000807@2ndQuadrant.com> Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 7bit X-Virus-Scanned: Maia Mailguard 1.0.1 X-Spam-Status: No, hits=-1.585 tagged_above=-10 required=5 tests=BAYES_00=-1.9, SARE_MILLIONSOF=0.315 X-Spam-Level: X-Archive-Number: 201107/12 X-Sequence-Number: 44224 On 6/22/11 11:42 , Greg Smith wrote: > On 06/22/2011 05:27 PM, Marcus Engene wrote: >> I have some tables with bitmask integers. Set bits are the >> interesting ones. Usually they are sparse. > > If it's sparse, create a partial index that just includes rows where > the bit is set: > http://www.postgresql.org/docs/current/static/indexes-partial.html > > You need to be careful the query uses the exact syntax as the one that > created the index for it to be used. But if you do that, it should be > able to pull the rows that match out quickly. > I ended up having a separate table with an index on. Though partial index solved another problem. Usually I'm a little bit annoyed with the optimizer and the developers religious "fix the planner instead of index hints". I must say that I'm willing to reconsider my usual stance to that. We have a large table of products where status=20 is a rare intermediate status. I added a... CREATE INDEX pond_item_common_x8 ON pond_item_common(pond_user, status) WHERE status = 20; ...and a slow 5s select with users who had existing status=20 items became very fast. Planner, I guess, saw the 10000 status 20 clips (out of millions of items) instead of like 5 different values of status and thus ignoring the index. Super! To my great amazement, the planner also managed to use the index when counting how many status=20 items there are in total: pond90=> explain analyze select pond90-> coalesce(sum(tt.antal),0) as nbr_in_queue pond90-> from pond90-> ( pond90(> select pond90(> pu.username pond90(> ,t.antal pond90(> from pond90(> ( pond90(> select pond90(> sum(1) as antal pond90(> ,pond_user pond90(> from pond90(> pond_item_common pond90(> where pond90(> status = 20 pond90(> group by pond_user pond90(> ) as t pond90(> ,pond_user pu pond90(> where pond90(> pu.objectid = t.pond_user pond90(> order by t.antal desc pond90(> ) as tt; QUERY PLAN -------------------------------------------------------------------------------------------------------------------------------------------------------------- Aggregate (cost=38079.45..38079.46 rows=1 width=8) (actual time=166.439..166.440 rows=1 loops=1) -> Sort (cost=38079.13..38079.18 rows=21 width=18) (actual time=166.009..166.085 rows=648 loops=1) Sort Key: (sum(1)) Sort Method: quicksort Memory: 67kB -> Nested Loop (cost=37903.66..38078.67 rows=21 width=18) (actual time=157.545..165.561 rows=648 loops=1) -> HashAggregate (cost=37903.66..37903.92 rows=21 width=4) (actual time=157.493..157.720 rows=648 loops=1) -> Bitmap Heap Scan on pond_item_common (cost=451.43..37853.37 rows=10057 width=4) (actual time=9.061..151.511 rows=12352 loops=1) Recheck Cond: (status = 20) -> Bitmap Index Scan on pond_item_common_x8 (cost=0.00..448.91 rows=10057 width=0) (actual time=5.654..5.654 rows=20051 loops=1) Index Cond: (status = 20) -> Index Scan using pond_user_pkey on pond_user pu (cost=0.00..8.30 rows=1 width=14) (actual time=0.011..0.012 rows=1 loops=648) Index Cond: (pu.objectid = pond_item_common.pond_user) Total runtime: 166.709 ms (13 rows) My hat's off to the dev gang. Impressive! Best, Marcus