I have a table with 50K rows. It is actually a PostGIS table.
The query has 4 parts (1 mandatory) (3 Optional)
- intersection box (a geography rectangle) with 4 lat,long (I use st_intersects) [Mandatory]
- Date Range (min, max) on a date field
- File type (a set of up to 8 text values) currently using IN( .....) but I can make that a temp table if needed. I see a lot of people don't like IN.
- Country (a text value).
I expect about 100 - 4,000 returned rows
If I create a compound index on the table, which column should I use first. The fine grained is probably the location (data is spread over the world). I currently have it as GIST index.
The other indexes would be BTREE.
My intuition says use fine grained, and course last. E.g. There are only about 12 file types, so that would be very big buckets for the index.
What do the PostgreSQL and PostGIS gurus (who know the internals of the system) say?
UPDATE:
Let me sharpen this question.
- I don't want anyone to have to do the work I should do. I respect your time too much. So I will get to the explain analyze later.
- All I was looking for was some pointers and tips and guidelines.
- I read this excellent little posting: https://devcenter.heroku.com/articles/postgresql-indexes#managing-and-maintaining-indexes about indexes
- What I normally do is create 4 separate indexes (geo-box, country name, file_type, and date) but what want to see what a composite query would do.
Tell me if any of these assumptions are wrong. (I am pretty new to the idea of compound indexes)
- Order is important. Choose as the first index the one that will cut the rows down the most (in my case the location (geography) which is a simple polygon or multi-polygon would do the best).
- Sometimes queries will skip indexes. But if I create a compound query with key (#1, #2, #3, #4) then even if the user creates something that asks for #1, #3 the planner will still use the single composite query, since they order is maintained.
- Normally I would create three BTREE queries, and one GIST (for the geography type). PostGIS does not support creating a compound out of multiple index-types. So I will have to use GIST the compound index. But that should not hurt things.
- If I do create some additional compound or single value indexes, the planner is smart enough to pick the most intelligent one.....
- Country Name can have about 250 different values, and is obviously strongly linked to location (geobox), but if the next best index for cutting down the row size is file_type I should use that next. I don't expect the users to often use country or date in their query sets.
- I do NOT have to worry about creating a compound index of 4 keys will greatly increase the size of the index data. I.e. if a one-key index would be 90% of the performance boost, it does not hurt to add 3 more items to make it compound. Conversely, I should really create both indexes. A Single geography index, and also a compound index, and let the planner figure out which is best, and it will take into account the size of the index table.
Again, I am not asking anyone to design my solution, I don't mooch of the the work of others. But I do need stuff that the PostGreSQL documentation does not tell me about implementation
[The reason I don't have a EXPLAIN result to show yet, is that I have to create this 25K row table from a 24M row table. It is taking more time than I thought. I am clustering things into 1,000 item groups, and letting the user query against the 25K row table. But my next question, will involve using the results of that query to go to the MASTER 25M row table and pull things out, and that is where the performance of the compound index will really HIT].
sample query below:
SELECT
public.product_list_meta_mv.cntry_name AS country,
public.product_list_meta_mv.product_producer AS producer,
public.product_list_meta_mv.product_name AS prod_name,
public.product_list_meta_mv.product_type AS ptype,
public.product_list_meta_mv.product_size AS size,
ST_AsGeoJSON(public.product_list_meta_mv.the_geom, 10, 2) AS outline
FROM
public.product_list_meta_mv
WHERE
public.product_list_meta_mv.cntry_name = 'Poland'
AND
ST_Intersects(public.product_list_meta_mv.the_geom,
st_geogfromtext('SRID=4326;POLYGON((21.23107910156250 51.41601562500000,
18.64379882812500 51.41601562500000,
18.64379882812500 48.69415283203130,
21.23107910156250 48.69415283203130,
21.23107910156250 51.41601562500000))'))
AND (date >= '1/2/1900 5:00:00 AM'
AND date <= '2/26/2014 10:26:44 PM')
AND (public.product_list_meta_mv.product_type in
('CIB10','DTED0','DTED1','DTED2','CIB01','CIB05')) ;
EXPLAIN ANALYZE results (I did not put in any compound indexes, and from the speed I am seeing I don't know if I need to).
"Bitmap Heap Scan on catalog_full cat (cost=4.33..37.49 rows=1 width=7428) (actual time=1.147..38.051 rows=35 loops=1)"
" Recheck Cond: ('0103000020E61000000100000005000000000000005838354000000000AEB0494000000000A0A7324000000000AEB0494000000000A0A73240000000006C5D48400000000058383540000000006C5D4840000000005838354000000000AEB04940'::geography && outline)"
" Filter: (((type)::text = ANY ('{CADRG,CIB10,DTED1,DTED2}'::text[])) AND (_st_distance('0103000020E61000000100000005000000000000005838354000000000AEB0494000000000A0A7324000000000AEB0494000000000A0A73240000000006C5D48400000000058383540000000006C5D4840000000005838354000000000AEB04940'::geography, outline, 0::double precision, false) < 1e-005::double precision))"
" Rows Removed by Filter: 61"
" -> Bitmap Index Scan on catalog_full_outline_idx (cost=0.00..4.33 rows=8 width=0) (actual time=0.401..0.401 rows=96 loops=1)"
" Index Cond: ('0103000020E61000000100000005000000000000005838354000000000AEB0494000000000A0A7324000000000AEB0494000000000A0A73240000000006C5D48400000000058383540000000006C5D4840000000005838354000000000AEB04940'::geography && outline)"
"Total runtime: 38.109 ms"
EXPLAIN ANALYZE SELECT pid,product_name,type,country,date,size,cocom,description,egpl_date,ST_AsGeoJSON(outline, 10, 2) AS outline
FROM portal.catalog_full AS cat
WHERE ST_Intersects(st_geogfromtext('SRID=4326;POLYGON((21.2200927734375 51.38031005859375, 18.65478515625 51.38031005859375, 18.65478515625 48.7298583984375, 21.2200927734375 48.7298583984375, 21.2200927734375 51.38031005859375))'), cat.outline)
AND (cat.type in ('CADRG','CIB10','DTED1','DTED2'))
EXPLAIN ANALYZE
for the query.