Reputation: 27573
I'm trying to speed up this PostgreSQL query to find previous entries "on this day" in past years from a table. I currently have the query below:
select * from sample
where date_part('month', "timestamp") = date_part('month', now())
and date_part('day', "timestamp") = date_part('day', now())
order by "timestamp" desc;
This seems to get the intended result, but it is running much slower than desired. Is there a better approach for comparing the current month & day?
Also, would there be any changes to do a similar search for "this hour" over the past years? Similar to the following:
select * from sample
where date_part('month', "timestamp") = date_part('month', now())
and date_part('day', "timestamp") = date_part('day', now())
and date_part('hour', "timestamp") = date_part('hour', now())
order by "timestamp" desc;
The data is time-series in nature, using TimescaleDB as the database. Here is the current definition:
CREATE TABLE public.sample (
"timestamp" timestamptz NOT NULL DEFAULT now(),
entity varchar(256) NOT NULL,
quantity numeric NULL
);
CREATE INDEX sample_entity_time_idx ON public.sample (entity, "timestamp" DESC);
CREATE INDEX sample_time_idx ON public.sample ("timestamp" DESC);
Upvotes: 3
Views: 119
Reputation: 48800
If you need the same day in all previous years that I would guess that the query would return 1/365th of the rows; that's a 0.27% selectivity. Great.
With that selectivity an index can speed up the query significantly. Now, since you are selecting non-consecutive rows you'll need a functional index. I would try:
create index ix1 on sample ((date_part('doy', "timestamp")));
Then, you can modify your query to:
select *
from sample
where date_part('doy', "timestamp") = date_part('doy', now())
order by "timestamp" desc;
For the current hour in the past years you would have an even better selectivity of around 1/365/24; that is 0.01%. Awesome.
create index ix2 on sample (
(date_part('doy', "timestamp")),
(date_part('hour', "timestamp"))
);
Then, the new query could look like:
select *
from sample
where date_part('doy', "timestamp") = date_part('doy', now())
and date_part('hour', "timestamp") = date_part('hour', now())
order by "timestamp" desc;
Please post the execution plans of these queries with the indexes created. I'm curious to see how well the perform.
Upvotes: 2