You are here
PostgreSQL: Casted Indexes
Dates in databases are a tedious thing. Sometimes a time value is recorded as a timestamp, at other times - probably in most cases - it is recorded as a date. Yet it can be useful to perform date-time queries using a representation of time distinct from what is recorded in the table. For example a database which records timestamps, but I want to look-up records by date.
To this end PostgreSQL supports indexing a table by a cast of a field.
Create A Sample
testing=> CREATE TABLE tstest (id int, ts timestamp);
CREATE TABLE
testing=> INSERT INTO TABLE tstest (1,'2018-09-01 12:30:16');
INSERT 0 1
testing=> INSERT INTO TABLE tstest (1,'2019-09-02 10:30:17');
INSERT 0 1
Create The Index
Now we can use the "::" operator to create an index on the ts field, but as a date rather than a timestamp.
testing=> create index tstest_tstodate on dtest ((ts::date));
CREATE INDEX
Testing
Now, will the database use this index? Yes, provided we cast ts as we do in the index.
testing=>SET ENABLE_SEQSCAN=off;
SET
testing=> EXPLAIN SELECT * FROM tstest WHERE ts::date='2019-09-02';
QUERY PLAN
-----------------------------------------------------------------------------
Index Scan using tsest_tstodate on tstest (cost=0.13..8.14 rows=1 width=12)
Index Cond: ((ts)::date = '2019-09-02'::date)
(2 rows)
For demonstration it is necessary to disable sequential scanning, ENABLE_SEQSCAN=off, otherwise with a table this small the PostgreSQL will never use any index.
Casting values in an index can be a significant performance win when you frequently query data in a form differing than its recorded form.