I want to improve this slow query, I thinking to add an index, but I don't know what index type is better to my case.
SELECT COUNT(*) ct FROM events
WHERE dtt AT TIME ZONE 'America/Santiago'
>= date(now() AT TIME ZONE 'America/Santiago') + interval '1s'
Query Plan:
"Aggregate (cost=128032.03..128032.04 rows=1 width=0) (actual time=3929.083..3929.083 rows=1 loops=1)"
" -> Seq Scan on events (cost=0.00..125937.68 rows=837742 width=0) (actual time=113.080..3926.972 rows=25849 loops=1)"
" Filter: (timezone('America/Santiago'::text, dtt) >= (date(timezone('America/Santiago'::text, now())) + '00:00:01'::interval))"
" Rows Removed by Filter: 2487386"
"Planning time: 0.179 ms"
"Execution time: 3929.136 ms"
Note: With the Erwin advices the query run a little faster but still I think isn't fast enough.
"Aggregate (cost=119667.76..119667.77 rows=1 width=0) (actual time=3687.151..3687.152 rows=1 loops=1)"
" -> Seq Scan on vehicle_events (cost=0.00..119667.14 rows=250 width=0) (actual time=104.635..3687.068 rows=469 loops=1)"
" Filter: (dtt >= timezone('America/Santiago'::text, date_trunc('day'::text, timezone('America/Santiago'::text, now()))))"
" Rows Removed by Filter: 2513337"
"Planning time: 0.164 ms"
"Execution time: 3687.204 ms"
For timestamp with time zone , the internally stored value is always in UTC (Universal Coordinated Time, traditionally known as Greenwich Mean Time, GMT ). An input value that has an explicit time zone specified is converted to UTC using the appropriate offset for that time zone.
Timestamp and Period can serve as an index. Lists of Timestamp and Period are automatically coerced to DatetimeIndex and PeriodIndex respectively.
The timestamp datatype allows you to store both date and time. However, it does not have any time zone data. It means that when you change the timezone of your database server, the timestamp value stored in the database will not change automatically.
GiST indexesThe Generalized Search Tree (GiST) is balanced, and it implements indexing schemes for new data types in a familiar balanced tree structure. It can index complex data such as geometric data and network address data. It can also implement different strategies such as B-tree or R-tree as well.
First, fix your query to make the predicate sargable:
SELECT count(*) AS ct
FROM events
WHERE dtt >= date_trunc('day', now() AT TIME ZONE 'America/Santiago')
AT TIME ZONE 'America/Santiago'
Use the column value as is and move all calculations to the parameter.
That's right, after deriving the local start of the day, apply AT TIME ZONE
a second time to convert the timestamp
back to timestamptz
again. Details:
now()
.. is the Postgres implementation for the SQL standard CURRENT_TIMESTAMP
. Both are 100 % equivalent, you can use either. It returns the current point in time as timestamptz
- the display of the value takes the time zone of the current session into consideration, but that's irrelevant for the value.
now()
AT TIME ZONE 'America/Santiago'
.. computes the local time for the given time zone. The resulting data type is timestamp
. We do this to allow for:
date_trunc(
now() AT TIME ZONE 'America/Santiago'
)
.. truncates the time component to get the local start of the day in 'America/Santiago', independent of the current time zone setting.
date_trunc('day', now() AT TIME ZONE 'America/Santiago')
AT TIME ZONE 'America/Santiago'
.. feeding the timestamp
to the AT TIME ZONE
construct we get the corresponding timestamptz
value (UTC internally) to compare the timestamptz
value dtt
to.
I removed the + interval '1s'
, suspecting you have just been abusing that to convert the date
to timestamp
. Use date_trunc()
instead to produce a timestamp
value.
Now, a plain (default) btree index on dtt
will do. Of course, the index will only be used, if the predicate is selective enough.
CREATE INDEX events_dtt_idx ON events (dtt);
If your important queries only consider recent rows, a partial index might help some more. Details:
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With