To try and lessen the load, I've done the following:
create index on t_read using brin (updated);create index on t_write using brin (updated);
This creates block range indexes on the updated column, which should allow reducing the number of blocks scanned for queries filtering by range of the updated column.
Before/after comparison:
winery=# explain analyze SELECT COUNT(*), SUM(bytes) FROM t_read WHERE bytes > 0 AND updated > NOW() - INTERVAL '5 minutes'; QUERY PLAN ----------------------------------------------------------------------------------------------------------------------------------------- Finalize Aggregate (cost=53358.01..53358.02 rows=1 width=16) (actual time=1055.497..1055.602 rows=1 loops=1) -> Gather (cost=53357.79..53358.00 rows=2 width=16) (actual time=1055.488..1055.594 rows=1 loops=1) Workers Planned: 2 Workers Launched: 0 -> Partial Aggregate (cost=52357.79..52357.80 rows=1 width=16) (actual time=1055.206..1055.207 rows=1 loops=1) -> Parallel Seq Scan on t_read (cost=0.00..52346.21 rows=2317 width=4) (actual time=0.057..1053.411 rows=19119 loops=1) Filter: ((bytes > 0) AND (updated > (now() - '00:05:00'::interval))) Rows Removed by Filter: 2922741 Planning Time: 0.163 ms Execution Time: 1055.658 ms(10 rows)winery=# create index on t_read using brin (updated);CREATE INDEXwinery=# explain analyze SELECT COUNT(*), SUM(bytes) FROM t_read WHERE bytes > 0 AND updated > NOW() - INTERVAL '5 minutes'; QUERY PLAN ----------------------------------------------------------------------------------------------------------------------------------------- Aggregate (cost=18891.89..18891.90 rows=1 width=16) (actual time=76.220..76.221 rows=1 loops=1) -> Bitmap Heap Scan on t_read (cost=5.94..18864.29 rows=5520 width=4) (actual time=0.258..75.239 rows=19091 loops=1) Recheck Cond: (updated > (now() - '00:05:00'::interval)) Rows Removed by Index Recheck: 348421 Filter: (bytes > 0) Rows Removed by Filter: 289 Heap Blocks: lossy=3840 -> Bitmap Index Scan on t_read_updated_idx (cost=0.00..4.56 rows=23452 width=0) (actual time=0.168..0.169 rows=38400 loops=1) Index Cond: (updated > (now() - '00:05:00'::interval)) Planning Time: 0.285 ms Execution Time: 76.275 ms(11 rows)
It seems that we're missing a cleanup procedure for outdated rows in these tables...