bug: sanction checks scan every player_sanctions chunk - #421
Conversation
player_sanctions is partitioned on created_at but only ever queried by player_steam_id, so chunk exclusion never prunes and each is_muted / is_gagged / is_banned call sequentially scans every chunk. There is no retention or compression policy on the other side of the trade, and the partitioning also forced the primary key from (id) to (id, created_at). Converts it back to a plain table, restoring PRIMARY KEY (id).
|
Correcting the premise here after profiling prod directly. The 34-164x speedup I measured came from a sample database with 86 chunks on Those checks are still 4.5% of prod DB time, but purely from being called 380 million times in 31 hours, and this migration does not reduce call count. So it will not measurably help prod. Still worth merging as correctness cleanup — a 10-row moderation table has no business being a hypertable, and it protects whichever instances have let chunks accumulate. Just shouldn't be merged expecting a prod win. |
|
Retracting my previous comment — it was wrong, and this PR is a significant prod win. I dismissed it because prod's buffer counts looked fine (4 buffers/call). That was the wrong signal. The cost isn't data volume, it's that chunk exclusion can never prune: the table is partitioned on Reproduced at prod's exact shape (PG 17.11, 10 sanction rows, 4 chunks, 477 players, index on That 0.066 ms matches prod's measured 0.067 ms per call almost exactly, so the repro is faithful. Same workload, hypertable vs plain:
The sanction checks are 11.2 hours of DB CPU over a 31-hour window on prod, so at 17x on the multi-player path this is worth roughly 8% of total database CPU. The commit message had it right the first time. |
player_sanctions is partitioned on created_at but only ever queried by player_steam_id, so chunk exclusion never prunes and each is_muted / is_gagged / is_banned call sequentially scans every chunk. There is no retention or compression policy on the other side of the trade, and the partitioning also forced the primary key from (id) to (id, created_at).
Converts it back to a plain table, restoring PRIMARY KEY (id).