CREATE TABLE transaction
(
client_id decimal(18, 0) NOT NULL,
trans_dttm timestamp,
division_code varchar(255),
...
)
One row size = approx 2Kb.
Usually table is searched by client_id and trans_dttm, but sometimes also by division_code, so:
create index "ix-transaction-client-trans_dttm-division"
on transaction (client_id,
trans_dttm desc,
division_code);
EXPLAIN (ANALYZE, BUFFERS)
select *
from transaction
where client_id = 123456
and (trans_dttm between TO_DATE('01.01.2020', 'dd.mm.yyyy') and TO_DATE('31.12.2022', 'dd.mm.yyyy'))
and (division_code in
('not_existing_code1', 'not_existing_code2'))
order by trans_dttm desc
limit 50 offset 0;
Limit (cost=0.57..14874.50 rows=50 width=2675) (actual time=703291.836..703291.845 rows=0 loops=1)
Buffers: shared hit=7981349 read=2078884
I/O Timings: read=683180.769
" -> Index Scan using ""ix-transaction-client-trans_dttm-division"" on transaction (cost=0.57..8350814.66 rows=28072 width=2675) (actual time=703291.834..703291.835 rows=0 loops=1)"
" Index Cond: ((client_id = '123456'::numeric) AND (trans_dttm >= to_date('01.01.2020'::text, 'dd.mm.yyyy'::text)) AND (trans_dttm <= to_date('31.12.2022'::text, 'dd.mm.yyyy'::text)))"
" Filter: ((division_code)::text = ANY ('{not_existing_code1,not_existing_code2}'::text[]))"
Rows Removed by Filter: 10000000
Buffers: shared hit=7981349 read=2078884
I/O Timings: read=683180.769
Planning Time: 0.258 ms
Execution Time: 703291.901 ms
In case when only one division_code passed: division_code in ('not_existing_code1'), the result is much better:
Limit (cost=0.57..810.34 rows=50 width=2675) (actual time=1479.254..1479.257 rows=0 loops=1)
Buffers: shared read=60245
I/O Timings: read=231.032
" -> Index Scan using ""ix-transaction-client-trans_dttm-division"" on transaction (cost=0.57..227318.91 rows=14036 width=2675) (actual time=1479.251..1479.253 rows=0 loops=1)"
" Index Cond: ((client_id = '123456'::numeric) AND (trans_dttm >= to_date('01.01.2020'::text, 'dd.mm.yyyy'::text)) AND (trans_dttm <= to_date('31.12.2022'::text, 'dd.mm.yyyy'::text)) AND ((division_code)::text = 'not_existing_code1'::text))"
Buffers: shared read=60245
I/O Timings: read=231.032
Planning Time: 1.031 ms
Execution Time: 1479.342 ms