A b-tree index, which is the default index type, can be used for operations >
, <
, >=
, <=
and =
i.e. ordering and equality.
When you use a function to transform the output in a way that transforms the value so it can't be looked up literally in the index then you can't use the index for a lookup.
This is the case with EXTRACT(day from ts)
. You can't do a b-tree lookup on the transformed column. Theoretically PostgreSQL could still do a b-tree index lookup if it could prove that the expression preserved ordering for all cases, as is true for extract(epoch from ts)
... but at the moment the optimizer doesn't know how to do that. Even if it could, extract(day from ...)
doesn't preserve ordering of inputs, in that a "lower" timestamp can have a higher "day", so a b-tree lookup cannot be used.
ts BETWEEN a AND b
is just a shorthand for writing ts >= a
and ts <= b
. Both are b-tree indexable operations.
You can create a new b-tree index on an expression, like
create index mytable_ts_day on mytable(extract(day from ts))
and this index then can be used for a matching expression like extract(day from ts) = 9
, or any other operator on the expression that's b-tree indexable. However, it means you have to maintain another index, which has a cost for each insert and update performed, and competes for cache space.