'PostgreSQL first query slow
I implemented cursor pagination. And for first rows it works realy well but the more I scroll down, the first query I send is slower. I run this query:
SELECT *
FROM "movie" "m"
INNER JOIN "movie_stats" "ms" ON "m"."uuid" = "ms"."movie_uuid"
WHERE (((("ms"."data"->'stat'->'overall'->>'total')::FLOAT), "ms"."movie_uuid") < (74.566, '50bca81c-4676-403e-8314-c721ba67646c')) AND ("m"."status" != 'deleted')
ORDER BY (("ms"."data"->'stat'->'overall'->>'total')::FLOAT) DESC NULLS LAST, "ms"."movie_uuid" DESC NULLS LAST
LIMIT 40
And after first run of query execution time is 444ms:
QUERY PLAN
Limit (cost=0.84..154.18 rows=40 width=565) (actual time=9.171..444.788 rows=40 loops=1)"
-> Nested Loop (cost=0.84..506620.20 rows=132160 width=565) (actual time=9.169..444.735 rows=40 loops=1)"
-> Index Scan using movie_stats_stat_overall_score_idx on movie_stats ""ms"" (cost=0.42..165910.17 rows=132443 width=741) (actual time=9.078..276.405 rows=40 loops=1)"
Index Cond: (ROW(((((data -> 'stat'::text) -> 'overall'::text) ->> 'total'::text))::double precision, movie_uuid) < ROW('74.566'::double precision, '50bca81c-4676-403e-8314-c721ba67646c'::uuid))"
-> Index Scan using movie_pkey on movie m (cost=0.42..2.56 rows=1 width=541) (actual time=4.188..4.188 rows=1 loops=40)"
Index Cond: (uuid = ""ms"".movie_uuid)"
Filter: (status <> 'deleted'::movie_status)"
Planning time: 1.140 ms
Execution time: 444.943 ms
But after executin this same query for second time exection time is only 1ms:
QUERY PLAN
Limit (cost=0.84..154.18 rows=40 width=1314) (actual time=0.066..0.791 rows=40 loops=1)"
-> Nested Loop (cost=0.84..506620.20 rows=132160 width=1314) (actual time=0.064..0.776 rows=40 loops=1)"
-> Index Scan using movie_stats_stat_overall_score_idx on movie_stats ""ms"" (cost=0.42..165910.17 rows=132443 width=749) (actual time=0.030..0.120 rows=40 loops=1)"
Index Cond: (ROW(((((data -> 'col'::text) -> 'overall'::text) ->> 'total'::text))::double precision, movie_uuid) < ROW('74.566'::double precision, '50bca81c-4676-403e-8314-c721ba67646c'::uuid))"
-> Index Scan using movie_pkey on movie m (cost=0.42..2.56 rows=1 width=541) (actual time=0.011..0.011 rows=1 loops=40)"
Index Cond: (uuid = ""asc"".movie_uuid)"
Filter: (status <> 'deleted'::movie_status)"
Planning time: 1.252 ms
Execution time: 0.916 ms
And this happens for each next 40 rows I go down. Can please someone explain me this. Thanks for help!
Solution 1:[1]
The first execution probably has to fetch data from disk, and the second already finds the data in shared buffers. You can diagnose that with EXPLAIN (ANALYZE, BUFFERS)
, which will show you the number of 8kB-blocks found in cache (hit
) and read from disk (read
).
For example:
Seq Scan on tab (...) (actual time=0.353..126.805 ...)
Buffers: shared read=1959
versus
Seq Scan on tab (...) (actual time=0.011..21.471 ...)
Buffers: shared hit=1959
If you need to speed that up, there are two possibilities:
Don't
SELECT *
and put all columns that you need in the query into the index. Then you can get an index-only scan, which may not hit the table at all if youVACUUM
it.Of course, that is probably not feasible if you need a lot of columns.
Get more RAM and try to keep the table in cache.
pg_prewarm
may help.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | Laurenz Albe |