From 5f89ff2b31b3322e633c52819870275d20fda38c Mon Sep 17 00:00:00 2001 From: Erik Johnston Date: Mon, 6 Jul 2026 12:59:11 +0100 Subject: [PATCH] Add an index on `sliding_sync_connections.last_used_ts` (#19912) Speeds up finding and deleting expired sliding sync connections in `delete_old_sliding_sync_connections`, which previously required a sequential scan. On matrix.org I have a suspicion that this might end up blocking some SSS connections during the delete, which can take minutes. Specifically, I think the deletion blocks this delete: https://github.com/element-hq/synapse/blob/ff19c034d300869e64878a15aed9a97f1cec59e4/synapse/storage/databases/main/sliding_sync.py#L233-L241 We didn't previously have an index because we wanted the postgres HOT updates, however we also limit the update frequency to once every 5 minutes, so hopefully this is fine. --------- Co-authored-by: Claude Opus 4.8 --- changelog.d/19912.misc | 1 + .../storage/databases/main/sliding_sync.py | 8 +++++++ .../main/delta/93/03_sss_pos_last_used.sql | 7 ------ ...ng_sync_connections_last_used_ts_index.sql | 22 +++++++++++++++++++ 4 files changed, 31 insertions(+), 7 deletions(-) create mode 100644 changelog.d/19912.misc create mode 100644 synapse/storage/schema/main/delta/94/06_sliding_sync_connections_last_used_ts_index.sql diff --git a/changelog.d/19912.misc b/changelog.d/19912.misc new file mode 100644 index 0000000000..e9491ab335 --- /dev/null +++ b/changelog.d/19912.misc @@ -0,0 +1 @@ +Speed up deletion of old sliding sync connections by adding an index. diff --git a/synapse/storage/databases/main/sliding_sync.py b/synapse/storage/databases/main/sliding_sync.py index d0943002b6..dbb9efc2ac 100644 --- a/synapse/storage/databases/main/sliding_sync.py +++ b/synapse/storage/databases/main/sliding_sync.py @@ -96,6 +96,14 @@ class SlidingSyncStore(SQLBaseStore): replaces_index="sliding_sync_membership_snapshots_user_id", ) + self.db_pool.updates.register_background_index_update( + update_name="sliding_sync_connections_last_used_ts_idx", + index_name="sliding_sync_connections_last_used_ts_idx", + table="sliding_sync_connections", + columns=("last_used_ts",), + where_clause="last_used_ts IS NOT NULL", + ) + if self.hs.config.worker.run_background_tasks: self.clock.looping_call( self.delete_old_sliding_sync_connections, diff --git a/synapse/storage/schema/main/delta/93/03_sss_pos_last_used.sql b/synapse/storage/schema/main/delta/93/03_sss_pos_last_used.sql index 747ba7a144..d8faac314d 100644 --- a/synapse/storage/schema/main/delta/93/03_sss_pos_last_used.sql +++ b/synapse/storage/schema/main/delta/93/03_sss_pos_last_used.sql @@ -18,10 +18,3 @@ -- may want to either backfill this or delete all rows with a NULL value (and -- then make it NOT NULL). ALTER TABLE sliding_sync_connections ADD COLUMN last_used_ts BIGINT; - --- Note: We don't add an index on this column to allow HOT updates on PostgreSQL --- to reduce the cost of the updates to the column. c.f. --- https://www.postgresql.org/docs/current/storage-hot.html --- --- We do query this column directly to find expired connections, but we expect --- that to be an infrequent operation and a sequential scan should be fine. diff --git a/synapse/storage/schema/main/delta/94/06_sliding_sync_connections_last_used_ts_index.sql b/synapse/storage/schema/main/delta/94/06_sliding_sync_connections_last_used_ts_index.sql new file mode 100644 index 0000000000..427d255759 --- /dev/null +++ b/synapse/storage/schema/main/delta/94/06_sliding_sync_connections_last_used_ts_index.sql @@ -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: +-- . + + +-- Add an index on `sliding_sync_connections(last_used_ts)` so that finding and +-- deleting expired connections (in `delete_old_sliding_sync_connections`) does +-- not require a sequential scan of the table. +-- +-- This is a partial index as we only ever query for rows with a non-NULL +-- `last_used_ts`. +INSERT INTO background_updates (ordering, update_name, progress_json) VALUES + (9406, 'sliding_sync_connections_last_used_ts_idx', '{}');