I have the following constructor (as a test):
CREATE TABLE product (id BIGSERIAL PRIMARY KEY, ext hstore);
CREATE INDEX ix_product_ext ON product USING GIN(ext);
INSERT
INTO product (id, ext)
SELECT id, ('size=>' || CEILING(10 + RANDOM() * 90) || ',mass=>' || CEILING(10 + RANDOM() * 90))::hstore
FROM generate_series(1, 100000) id;
I have the following query, which works ok:
SELECT COUNT(id)
FROM (
SELECT id
FROM product
WHERE (ext->'size')::INT >= 41
AND (ext->'mass')::INT <= 20
) T
But I believe the correct way to do this is using the @> operator. I have the following, but it gives a syntax error:
SELECT COUNT(id)
FROM (
SELECT id
FROM product
WHERE ext @> 'size>=41,mass<=20'
) T
How should I write this?
Reading hstore documentation your (last query) size>=41
does not mean "when size is greater or equal than 41":
text => text make single-pair hstore
Following that you can't write mass<=20
, because there is no such operation. Using @>
operator:
hstore @> hstore does left operand contain right?
you can write:
SELECT count(id)
FROM product
WHERE ext @> 'size=>41,mass=>20';
However it takes only these products where size is equal to 41 and mass is equal to 20.
Your initial attempt is correct but you need to use (partial) btree indexes and bitmap index scans to rely on it:
create index on product(((ext->'size')::int)) where ((ext->'size') is not null);
The same for mass, and if the planner doesn't get it on the spot add two where clauses, ie where ext->'size' is not null
and the same for mass.
If there is a pattern of some kind (which is likely, since most products with a size also have a mass), potentially create a multicolumn index combining the two - one sac, the other desc.
The gin index as you wrote it, along with the accompanying query (with a syntax error) will basically do the same thing but unordered; it'll be slower.