The table in question looks similar to this:
create table metrics_measurement
(
id bigint generated by default as identity
constraint metrics_measurement_pkey
primary key,
measured_at timestamp with time zone not null,
measured_value double precision not null,
metric_id integer not null
constraint metrics_measurement_metric_id_24fcec65_fk_metrics_metric_id
references metrics_metric
deferrable initially deferred,
processed_into_aggregate boolean not null,
created_at timestamp with time zone not null,
updated_at timestamp with time zone not null
);
The query in question is:
SELECT *
FROM "metrics_measurement"
WHERE "metrics_measurement"."metric_id" = 6433
ORDER BY "metrics_measurement"."measured_at" ASC
LIMIT 1;
What I would expect to happen is Postgres uses the index on metric_id to filter down to the relevant rows and then do a sort on the remainder. This is what it's actually trying to do:
Limit (cost=722051.34..722051.46 rows=1 width=45) (actual time=50814.355..50814.446 rows=1 loops=1)
-> Gather Merge (cost=722051.34..770982.43 rows=419380 width=45) (actual time=50814.354..50814.444 rows=1 loops=1)
Workers Planned: 2
Workers Launched: 0
-> Sort (cost=721051.32..721575.54 rows=209690 width=45) (actual time=50814.141..50814.141 rows=1 loops=1)
Sort Key: measured_at
Sort Method: top-N heapsort Memory: 25kB
-> Parallel Seq Scan on metrics_measurement (cost=0.00..720002.87 rows=209690 width=45) (actual time=24.851..50765.952 rows=489909 loops=1)
Filter: (metric_id = 6433)
Rows Removed by Filter: 48938488
Planning Time: 0.140 ms
Execution Time: 50814.467 ms
If I SET enambe_seqscan TO OFF
, then it does as expected and is like 2 orders of magnitude faster:
Limit (cost=723454.64..723454.75 rows=1 width=45) (actual time=494.140..494.773 rows=1 loops=1)
-> Gather Merge (cost=723454.64..772444.06 rows=419880 width=45) (actual time=494.139..494.771 rows=1 loops=1)
Workers Planned: 2
Workers Launched: 2
-> Sort (cost=722454.61..722979.46 rows=209940 width=45) (actual time=481.618..481.619 rows=1 loops=3)
Sort Key: measured_at
Sort Method: top-N heapsort Memory: 25kB
Worker 0: Sort Method: top-N heapsort Memory: 25kB
Worker 1: Sort Method: top-N heapsort Memory: 25kB
-> Parallel Bitmap Heap Scan on metrics_measurement (cost=5753.32..721404.91 rows=209940 width=45) (actual time=76.833..467.373 rows=163306 loops=3)
Recheck Cond: (metric_id = 6433)
Heap Blocks: exact=2308
-> Bitmap Index Scan on metrics_measurement_metric_id_24fcec65 (cost=0.00..5627.35 rows=503855 width=0) (actual time=85.310..85.310 rows=489917 loops=1)
Index Cond: (metric_id = 6433)
Planning Time: 0.140 ms
Execution Time: 494.802 ms
I've already attempted ANALYZE
ing the table and running alter table metrics_measurement alter metric_id set statistics 10000
and then ANALYZE
ing again and the planner still refuses to use the index available to it. I've tried to look at the metrics and such it uses to see what's wrong but it's a bit out of my knowledge to know what to look for there.
So, my question, short of setting SET enable_seqscan TO OFF
in every connection (which I feel like would be Bad), what would be the next steps in figuring out why Postgres isn't doing the optimal thing here?