Skip to content

Commit bfb3a6e

Browse files
authored
Improve performance of device deletion by adding missing index. (#18582)
<ol> <li> Reorder columns in `event_txn_id_device_id_txn_id` index \ This now satisfies the foreign key on `(user_id, device_id)` making reverse lookups, as needed for device deletions, more efficient. This improves device deletion performance by on the order of 8 to 10× on matrix.org. </li> </ol> Rationale: ## On the `event_txn_id_device_id` table: We currently have this index: ```sql -- This ensures that there is only one mapping per (room_id, user_id, device_id, txn_id) tuple. CREATE UNIQUE INDEX IF NOT EXISTS event_txn_id_device_id_txn_id ON event_txn_id_device_id(room_id, user_id, device_id, txn_id); ``` The main way we use this table is ```python return await self.db_pool.simple_select_one_onecol( table="event_txn_id_device_id", keyvalues={ "room_id": room_id, "user_id": user_id, "device_id": device_id, "txn_id": txn_id, }, retcol="event_id", allow_none=True, desc="get_event_id_from_transaction_id_and_device_id", ) ``` But this foreign key is relatively unsupported, making deletions in the devices table inefficient (full index scan on the above index): ```sql FOREIGN KEY (user_id, device_id) REFERENCES devices (user_id, device_id) ON DELETE CASCADE ``` I propose re-ordering the columns in that index to: `(user_id, device_id, room_id, txn_id)` (by replacing it). That way the foreign key back-check can rely on the prefix of this index, but it's still useful for the original purpose it was made for. It doesn't take any extra disk space and does not harm write performance (because the same amount of writing work needs to be performed). --------- Signed-off-by: Olivier 'reivilibre <oliverw@matrix.org>
1 parent 8afea3d commit bfb3a6e

3 files changed

Lines changed: 29 additions & 0 deletions

File tree

changelog.d/18582.bugfix

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Improve performance of device deletion by adding missing index.

synapse/storage/databases/main/events_worker.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -349,6 +349,19 @@ def get_chain_id_txn(txn: Cursor) -> int:
349349
where_clause="type = 'm.room.member'",
350350
)
351351

352+
# Added to support efficient reverse lookups on the foreign key
353+
# (user_id, device_id) when deleting devices.
354+
# We already had a UNIQUE index on these 4 columns but out-of-order
355+
# so replace that one.
356+
self.db_pool.updates.register_background_index_update(
357+
update_name="event_txn_id_device_id_txn_id2",
358+
index_name="event_txn_id_device_id_txn_id2",
359+
table="event_txn_id_device_id",
360+
columns=("user_id", "device_id", "room_id", "txn_id"),
361+
unique=True,
362+
replaces_index="event_txn_id_device_id_txn_id",
363+
)
364+
352365
def get_un_partial_stated_events_token(self, instance_name: str) -> int:
353366
return (
354367
self._un_partial_stated_events_stream_id_gen.get_current_token_for_writer(
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
--
2+
-- This file is licensed under the Affero General Public License (AGPL) version 3.
3+
--
4+
-- Copyright (C) 2025 New Vector, Ltd
5+
--
6+
-- This program is free software: you can redistribute it and/or modify
7+
-- it under the terms of the GNU Affero General Public License as
8+
-- published by the Free Software Foundation, either version 3 of the
9+
-- License, or (at your option) any later version.
10+
--
11+
-- See the GNU Affero General Public License for more details:
12+
-- <https://www.gnu.org/licenses/agpl-3.0.html>.
13+
14+
INSERT INTO background_updates (ordering, update_name, progress_json) VALUES
15+
(9207, 'event_txn_id_device_id_txn_id2', '{}');

0 commit comments

Comments
 (0)