Thanks!
Going through this of how to go backwards from a query to SQLAlchemy
is the part that I was missing. I'm personally not wedded to the
Postgres method, actually the opposite. But it's also been the one
call that didn't stall massively on larger datasets.
The performance characteristics are pretty strange, as the one that
you suggested at first went up way high, but goes down again when you
disable seqscan..
Here are the explain outputs (ignoring my version, as that is even
slower and actually pages out to disk for sorting due to having too
many rows)
And frankly, I do not have the knowledge I need to understand "why"
the difference between seqscan enabled and disabled is happening.
Guessing that my indexes aren't correctly set up, but as said, I lack
the necessary DBA skills for this. I feel as if I'm in over my head.
Now, since this query is turning out to be a whole lot more annoying
to work on than I'd ever imagined, is there a better way of
representing my data store for this?
Duplicating the latest timestamp in a 1:1 relationship, or something else?
//D.S.
caramel=# explain analyze SELECT (c).csr_id, (c).not_before,
(c).not_after FROM (SELECT (SELECT c FROM certificate c WHERE
c.csr_id=
csr.id ORDER BY c.not_after DESC LIMIT 1) AS c FROM csr
offset 0) s;
QUERY PLAN
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Subquery Scan on s (cost=0.00..989627.43 rows=196332 width=32)
(actual time=4.288..6130.111 rows=196332 loops=1)
-> Limit (cost=0.00..987664.11 rows=196332 width=4) (actual
time=4.286..6030.657 rows=196332 loops=1)
-> Index Only Scan using csr_rejected_idx4 on csr
(cost=0.00..987664.11 rows=196332 width=4) (actual
time=4.284..5968.457 rows=196332 loops=1)
Heap Fetches: 0
SubPlan 1
-> Limit (cost=0.00..4.96 rows=1 width=2029)
(actual time=0.029..0.029 rows=1 loops=196332)
-> Index Scan Backward using
certificate_csr_id_not_after_idx on certificate c (cost=0.00..24.80
rows=5 width=2029) (actual time=0.028..0.028 rows=1 loops=196332)
Index Cond: (csr_id =
csr.id)
Total runtime: 6163.357 ms
caramel=# explain analyze select c.csr_id, c.not_before, c.not_after
from certificate as c
join csr on c.csr_id =
csr.id
where c.csr_id = (
select csr_id from certificate where c.csr_id=
csr.id
order by c.not_after desc limit 1
);
QUERY PLAN
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Hash Join (cost=16391.49..395380.31 rows=5 width=20) (actual
time=21552.556..21574.528 rows=1 loops=1)
Hash Cond: (c.csr_id =
csr.id)
Join Filter: ((SubPlan 1) = c.csr_id)
Rows Removed by Join Filter: 571550
-> Seq Scan on certificate c (cost=0.00..289383.98 rows=555898
width=20) (actual time=1.029..16866.441 rows=571551 loops=1)
-> Hash (cost=13937.34..13937.34 rows=196332 width=4) (actual
time=88.475..88.475 rows=196332 loops=1)
Buckets: 32768 Batches: 1 Memory Usage: 6903kB
-> Index Only Scan using csr_rejected_idx4 on csr
(cost=0.00..13937.34 rows=196332 width=4) (actual time=0.018..42.298
rows=196332 loops=1)
Heap Fetches: 0
SubPlan 1
-> Limit (cost=0.00..0.14 rows=1 width=4) (actual
time=0.006..0.006 rows=1 loops=571551)
-> Result (cost=0.00..75707.40 rows=555898 width=4)
(actual time=0.006..0.006 rows=1 loops=571551)
One-Time Filter: (c.csr_id =
csr.id)
-> Index Only Scan using certificate_csr_id_idx on
certificate (cost=0.00..75707.40 rows=555898 width=4) (actual
time=0.005..0.005 rows=1 loops=571551)
Heap Fetches: 0
Total runtime: 21574.638 ms
(16 rows)
caramel=# SET enable_seqscan = OFF;
SET
caramel=# explain analyze select c.csr_id, c.not_before, c.not_after
from certificate as c
join csr on c.csr_id =
csr.id
where c.csr_id = (
select csr_id from certificate where c.csr_id=
csr.id
order by c.not_after desc limit 1
);
QUERY PLAN
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Merge Join (cost=1600.52..2226996.44 rows=5 width=20) (actual
time=0.026..12796.020 rows=1 loops=1)
Merge Cond: (
csr.id = c.csr_id)
Join Filter: ((SubPlan 1) = c.csr_id)
Rows Removed by Join Filter: 571550
-> Index Only Scan using csr_rejected_idx4 on csr
(cost=0.00..13937.34 rows=196332 width=4) (actual time=0.007..422.941
rows=196332 loops=1)
Heap Fetches: 0
-> Index Scan using certificate_csr_id_idx on certificate c
(cost=0.00..2127137.37 rows=555898 width=20) (actual
time=0.005..8224.643 rows=571551 loops=1)
SubPlan 1
-> Limit (cost=0.00..0.14 rows=1 width=4) (actual
time=0.006..0.006 rows=1 loops=571551)
-> Result (cost=0.00..75707.40 rows=555898 width=4)
(actual time=0.006..0.006 rows=1 loops=571551)
One-Time Filter: (c.csr_id =
csr.id)
-> Index Only Scan using certificate_csr_id_idx on
certificate (cost=0.00..75707.40 rows=555898 width=4) (actual
time=0.005..0.005 rows=1 loops=571551)
Heap Fetches: 0
Total runtime: 12798.066 ms
(14 rows)
caramel=# \d certificate
Table "public.certificate"
Column | Type |
Modifiers
------------+-----------------------------+----------------------------------------------------------
id | integer | not null default
nextval('certificate_id_seq'::regclass)
pem | text | not null
not_before | timestamp without time zone | not null
not_after | timestamp without time zone | not null
csr_id | integer | not null
Indexes:
"certificate_pkey" PRIMARY KEY, btree (id)
"certificate_csr_id_idx" btree (csr_id)
"certificate_csr_id_not_after_idx" btree (csr_id, not_after)
Foreign-key constraints:
"certificate_csr_id_fkey" FOREIGN KEY (csr_id) REFERENCES csr(id)
caramel=# \d csr
Table "public.csr"
Column | Type | Modifiers
------------+-----------------------+--------------------------------------------------
id | integer | not null default
nextval('csr_id_seq'::regclass)
sha256sum | character(64) | not null
pem | text | not null
orgunit | character varying(64) |
commonname | character varying(64) |
rejected | boolean |
Indexes:
"csr_pkey" PRIMARY KEY, btree (id)
"csr_sha256sum_key" UNIQUE CONSTRAINT, btree (sha256sum)
"csr_rejected_idx4" btree (id, rejected)
Referenced by:
TABLE "accesslog" CONSTRAINT "accesslog_csr_id_fkey" FOREIGN KEY
(csr_id) REFERENCES csr(id)
TABLE "certificate" CONSTRAINT "certificate_csr_id_fkey" FOREIGN
KEY (csr_id) REFERENCES csr(id)
TABLE "icky" CONSTRAINT "icky_csr_id_fkey" FOREIGN KEY (csr_id)
REFERENCES csr(id)