I have millions of records in this table using Amazon Aurora Postgres 10.7:
create table "somedb"."sometable"
(
id varchar(4096) not null constraint "sometable_pkey" primary key,
tag varchar(255) not null,
json jsonb not null
);
Example row:
{"id": "abc", "ts": 1580879910, "data": "my stuff"}
I have these queries that take dozens of seconds:
SELECT jsonData->'data'
WHERE (jsonData->>'ts' >= '1576000473')
ORDER BY jsonData->>'ts' ASC LIMIT 100 OFFSET 50000;
I’m trying to improve performance here, and these are all the indexes that I tried, but at most I get an INDEX SCAN in the query plan at best.
create index "sometable_ts"
on "somedb"."sometable" ((jsondata -> 'ts'::text));
create index "sometable_ts-int"
on "somedb"."sometable" using btree (((jsondata ->> 'ts')::integer));
I adjust my queries as well to: ORDER BY (jsonData->>'ts')::integer
, but nothing.
Best plan:
Limit (cost=613080.18..613149.46 rows=100 width=356) (actual time=24934.492..24937.344 rows=100 loops=1)
-> Index Scan using "sometable_ts-int" on "sometable" (cost=0.43..3891408.61 rows=5616736 width=356) (actual time=0.068..24889.459 rows=885000 loops=1)
Index Cond: (((jsondata ->> 'ts'::text))::integer >= 1576000473)
Planning time: 0.145 ms
Execution time: 24937.381 ms
Can anyone recommend a way to adjust the indexes or queries for these to become faster? Thanks!
Advertisement
Answer
Using OFFSET
like this will always cause bad performance.
You should use keyset pagination:
Create this index:
CREATE INDEX ON somedb.sometable (id, (jsonData->>'ts'));
Then, to paginate, your first query is:
SELECT jsonData->'data'
FROM somedb.sometable
WHERE jsonData->>'ts' >= '1576000473'
ORDER BY jsonData->>'ts', id
LIMIT 100;
Remember jsonData->>'ts'
and id
from the last result row you got in last_ts
and last_id
.
Your next page is found with
SELECT jsonData->'data'
FROM somedb.sometable
WHERE (jsonData->>'ts', id) > (last_ts, last_id)
ORDER BY jsonData->>'ts', id
LIMIT 100;
Keep going like this, and retrieving the 500th page will be as fast as retrieving the first.