Обсуждение: Queries with conditions using bitand operator

Поиск
Список
Период
Сортировка

Queries with conditions using bitand operator

От
Elias Ghanem
Дата:
Hi,
I have table "ARTICLE" containing a String a field "STATUS" that
represents a number in binary format (for ex: 10011101).
My application issues queries with where conditions that uses BITAND
operator on this field (for ex: select * from article where status & 4 = 4).
Thus i'm facing performance problemes with these select queries: the
queries are too slow.
Since i'm using the BITAND operator in my conditions, creating an index
on the status filed is useless
  and since the second operator variable (status & 4 = 4; status & 8 =
8; status & 16 = 16...) a functional index is also usless (because a
functional index require the use of a function that accept only table
column as input parameter: constants are not accepted).
So is there a way to enhance the performance of these queries?
Thanks,
Elias

Re: Queries with conditions using bitand operator

От
Andy Colson
Дата:
On 07/13/2010 06:48 AM, Elias Ghanem wrote:
> Hi,
> I have table "ARTICLE" containing a String a field "STATUS" that represents a number in binary format (for ex:
10011101).
> My application issues queries with where conditions that uses BITAND operator on this field (for ex: select * from
articlewhere status & 4 = 4). 
> Thus i'm facing performance problemes with these select queries: the queries are too slow.
> Since i'm using the BITAND operator in my conditions, creating an index on the status filed is useless
> and since the second operator variable (status & 4 = 4; status & 8 = 8; status & 16 = 16...) a functional index is
alsousless (because a functional index require the use of a function that accept only table column as input parameter:
constantsare not accepted). 
> So is there a way to enhance the performance of these queries?
> Thanks,
> Elias
>

How many flags are there?  If its not too many you could make a separate column for each... but then that would be lots
ofindexes too... 

One other thought I had was to make it a text column, turn the flags into words (space separated) and use full text
indexes.

I played around with int's and string's but I couldnt find a way using the & operator.

-Andy

Re: Queries with conditions using bitand operator

От
Joe Conway
Дата:
On 07/13/2010 04:48 AM, Elias Ghanem wrote:
> Hi,
> I have table "ARTICLE" containing a String a field "STATUS" that
> represents a number in binary format (for ex: 10011101).
> My application issues queries with where conditions that uses BITAND
> operator on this field (for ex: select * from article where status & 4 =
> 4).
> Thus i'm facing performance problemes with these select queries: the
> queries are too slow.
> Since i'm using the BITAND operator in my conditions, creating an index
> on the status filed is useless
>  and since the second operator variable (status & 4 = 4; status & 8 = 8;
> status & 16 = 16...) a functional index is also usless (because a
> functional index require the use of a function that accept only table
> column as input parameter: constants are not accepted).
> So is there a way to enhance the performance of these queries?

You haven't given a lot of info to help us help you, but would something
along these lines be useful to you?

drop table if exists testbit;
create table testbit(
 id serial primary key,
 article text,
 status int
);

insert into testbit (article, status) select 'article ' ||
generate_series::text, generate_series % 256 from
generate_series(1,1000000);

create index idx1 on testbit(article) where status & 1 = 1;
create index idx2 on testbit(article) where status & 2 = 2;
create index idx4 on testbit(article) where status & 4 = 4;
create index idx8 on testbit(article) where status & 8 = 8;
create index idx16 on testbit(article) where status & 16 = 16;
create index idx32 on testbit(article) where status & 512 = 512;

update testbit set status = status + 512 where id in (42, 4242, 424242);
explain analyze select * from testbit where status & 512 = 512;
                          QUERY PLAN
------------------------------------------------------------------
 Index Scan using idx32 on testbit  (cost=0.00..4712.62 rows=5000
                width=22) (actual time=0.080..0.085 rows=3 loops=1)
 Total runtime: 0.170 ms


HTH,

Joe

--
Joe Conway
credativ LLC: http://www.credativ.us
Linux, PostgreSQL, and general Open Source
Training, Service, Consulting, & Support


Вложения

Re: Queries with conditions using bitand operator

От
valgog
Дата:
One of the possibilities would be to decompose your bitmap into an
array of base integers and then create a GIN (or GIST) index on that
array (intarray contrib package). This would make sense if your
articles are distributed relatively equally and if do not do big ORDER
BY and then LIMIT/OFFSET queries, that usually will need to sort the
results gotten from the GIN index.
As your are also probably doing some tsearch queries on the articles,
you can actually build combined (tverctor, intarray) GIN/GIST index to
optimize your searches.

A simple function, that can help you stripping your bitmap integer to
array of positions could look like:

-- DROP FUNCTION utils.bitmap_to_position_intarray(bitmap integer);

CREATE OR REPLACE FUNCTION utils.bitmap_to_position_intarray(bitmap
integer)
  RETURNS integer[] AS
$BODY$
-- test
-- select utils.bitmap_to_position_intarray(5);
-- test performance
-- select utils.bitmap_to_position_intarray(s.i) from
generate_series(1, 10000) as s(i);
--

SELECT ARRAY(
  SELECT s.i + 1 -- here we do +1 to make the position of the first
bit 1
    FROM generate_series(0, 31) as s(i)
   WHERE $1 & ( 1 << s.i ) > 0
  );
$BODY$
  LANGUAGE SQL IMMUTABLE STRICT;

You can create a GIN index directly using this function over your
bitmap field and then using array set operations will make the planner
to use the GIN index (more information about these indexes here:
http://www.postgresql.org/docs/8.4/interactive/textsearch-indexes.html):

CREATE INDEX idx_article_status_gin ON article USING
gin( (utils.bitmap_to_position_intarray(STATUS) ) );

and then you can do:

SELECT * FROM article WHERE utils.bitmap_to_position_intarray(STATUS)
&& ARRAY[1,5];

or

SELECT * FROM article WHERE utils.bitmap_to_position_intarray(STATUS)
&& utils.bitmap_to_position_intarray(5);

Have a look on the possible array set operations in
http://www.postgresql.org/docs/8.4/interactive/intarray.html.

Otherwise a solution from Jeo Conway to create separate indexes for
each bit also is worth to be looked up. This has actually drawbacks,
that you cannot look up combinations of bits efficiently. As an
advantage in the example from Jeo, you can efficiently do ORDER BY
article (or any other field, that you add into these limited
indexes).