Schema:
Column | Type
----------------------+--------------------------
id | integer
event_id | integer
started_at | timestamp with time zone
ended_at | timestamp with time zone
created_at | timestamp with time zone
"event_seat_state_lookup_pkey" PRIMARY KEY, btree (id)
"event_seating_lookup_created_at_idx" btree (created_at)
"event_seating_lookup_created_at_idx2" gist (created_at)
Query:
SELECT id
FROM event_seating_lookup esl1
WHERE
tstzrange(now() - interval '1 hour', now() + interval '1 hour', '[)') @> esl1.created_at;
Explain analyze:
Table with <100k rows.
Seq Scan on event_seating_lookup esl1 (cost=0.00..1550.30 rows=148 width=4) (actual time=0.013..19.956 rows=29103 loops=1)
Filter: (tstzrange((now() - '01:00:00'::interval), (now() + '01:00:00'::interval), '[)'::text) @> created_at)
Buffers: shared hit=809
Planning Time: 0.110 ms
Execution Time: 21.942 ms
Table with 1M+ rows:
Seq Scan on event_seating_lookup esl1 (cost=10000000000.00..10000042152.75 rows=5832 width=4) (actual time=0.009..621.895 rows=1166413 loops=1)
Filter: (tstzrange((now() - '01:00:00'::interval), (now() + '01:00:00'::interval), '[)'::text) @> created_at)
Buffers: shared hit=12995
Planning Time: 0.092 ms
Execution Time: 697.927 ms
I have tried:
VACUUM FULL event_seating_lookup;
VACUUM event_seating_lookup;
VACUUM ANALYZE event_seating_lookup;
SET enable_seqscan = OFF;
Problem:
event_seating_lookup_created_at_idx or event_seating_lookup_created_at_idx2 indexes are not being used.
Notes:
- PostgreSQL 11.1.
btree_gistextension is installed.- I have tried equivalent setup with
created_at timestamp without time zoneand usingtsrange; same result. - I understand that rewriting the query with
>=,<checks would make it use the btree index. The question is what is the reason the index is not used with thetstzrangecontainment operator and if there is a way to make it work.
ST_DWithin()): rewrite functions with the right operators to target certain indexes. So the general approach can make sense. Just make sure the function can be inlined. See: https://dba.stackexchange.com/a/212199/3684. And declare itIMMUTABLEsince it is. (Not sure about your handling of bounds ...) – Erwin Brandstetter Jan 11 '19 at 18:36immutableattribute. Thats what I did at first, but then I got feedback saying that "you should usually avoid declaring inlinable scalar sql funcs as immutable. https://wiki.postgresql.org/wiki/Inlining_of_SQL_functions read it; declaring an sql function immutable can only make it less inlinable. for scalar functions, that is; and once the function is inlined, what matters for const-simplification is the operators and functions inside the body, which are not affected by an "immutable" declaration on the function itself" – Gajus Jan 11 '19 at 18:42upper(),upper_inc(),lower(),lower_inc()- I checked!) you should declare it as such. That's not to help inlining, but it allows various other optimizations. – Erwin Brandstetter Jan 11 '19 at 18:52