Use better statistics for device_lists_changes_in_room in postgres (#20495)

The default statistics for `device_lists_changes_in_room` were often
wrong, underestimating the number of distinct values of `room_id` and
`stream_id` columns. This meant in Postgres 18 that it used the wrong
index, leading to large amounts of IO.

In Postgres 18 the query planner now supports "skip scans", which means
more of the indexes are available to be used, and thus makes it more
important to have accurate statistics.

The problematic query was operating on an array of room IDs and a range
of stream IDs. Previously, it would use the index on `(room_id,
stream_id)`. After upgrade, it started using `(stream_id, room_id)` on
the assumption that we were matching the majority of all rooms and thus
may as well pull out all rows matching the stream ID range.
This commit is contained in:
Erik Johnston authored and GitHub committed 2026-11-13 10:08:53 +00:00
1 parent c3e57a4e30
commit 367f7fc52e
2 files changed
+23

No files matched your search

+1
View File
@@ -0,0 +1 @@
Mitigate potential database performance issues with Postgres 18 by updating the statistics for `device_lists_changes_in_room`.
@@ -0,0 +1,22 @@
--
-- This file is licensed under the Affero General Public License (AGPL) version 3.
--
-- Copyright (C) 2026 Element Creations Ltd
--
-- This program is free software: you can redistribute it and/or modify
-- it under the terms of the GNU Affero General Public License as
-- published by the Free Software Foundation, either version 3 of the
-- License, or (at your option) any later version.
--
-- See the GNU Affero General Public License for more details:
-- <https://www.gnu.org/licenses/agpl-3.0.html>.
-- We need to increase the number of rows to sample for `room_id` column,
-- otherwise the stats will underestimate the number of distinct rooms and make
-- the query planner use the wrong index.
ALTER TABLE device_lists_changes_in_room ALTER COLUMN room_id SET STATISTICS 1000;
-- Manually tell the query planner that we expect the number of distinct values
-- in the `stream_id` column to be proportional to the number of rows.
ALTER TABLE device_lists_changes_in_room ALTER COLUMN stream_id SET (n_distinct = -0.05);