Add membership column to current_state_events table.

It turns out that doing a join is surprisingly expensive for the DB to
do when room_membership table is larger than the disk cache.
This commit is contained in:
Erik Johnston 2019-07-17 15:33:37 +01:00
parent c831c5b2bb
commit 6de09e07a6
5 changed files with 41 additions and 20 deletions

View File

@ -918,8 +918,6 @@ class EventsStore(
min_stream_order = events_and_contexts[0][0].internal_metadata.stream_ordering min_stream_order = events_and_contexts[0][0].internal_metadata.stream_ordering
max_stream_order = events_and_contexts[-1][0].internal_metadata.stream_ordering max_stream_order = events_and_contexts[-1][0].internal_metadata.stream_ordering
self._update_current_state_txn(txn, state_delta_for_room, min_stream_order)
self._update_forward_extremities_txn( self._update_forward_extremities_txn(
txn, txn,
new_forward_extremities=new_forward_extremeties, new_forward_extremities=new_forward_extremeties,
@ -993,6 +991,10 @@ class EventsStore(
backfilled=backfilled, backfilled=backfilled,
) )
# We call this last as it assumes we've inserted the events into
# room_memberships, where applicable.
self._update_current_state_txn(txn, state_delta_for_room, min_stream_order)
def _update_current_state_txn(self, txn, state_delta_by_room, stream_id): def _update_current_state_txn(self, txn, state_delta_by_room, stream_id):
for room_id, current_state_tuple in iteritems(state_delta_by_room): for room_id, current_state_tuple in iteritems(state_delta_by_room):
to_delete, to_insert = current_state_tuple to_delete, to_insert = current_state_tuple
@ -1062,16 +1064,16 @@ class EventsStore(
), ),
) )
self._simple_insert_many_txn( # We include the membership in the current state table, hence we do
txn, # a lookup when we insert. This assumes that all events have already
table="current_state_events", # been inserted into room_memberships.
values=[ txn.executemany(
{ """INSERT INTO current_state_events
"event_id": ev_id, (room_id, type, state_key, event_id, membership)
"room_id": room_id, VALUES (?, ?, ?, ?, (SELECT membership FROM room_memberships WHERE event_id = ?))
"type": key[0], """,
"state_key": key[1], [
} (room_id, key[0], key[1], ev_id, ev_id)
for key, ev_id in iteritems(to_insert) for key, ev_id in iteritems(to_insert)
], ],
) )

View File

@ -27,7 +27,7 @@ logger = logging.getLogger(__name__)
# Remember to update this number every time a change is made to database # Remember to update this number every time a change is made to database
# schema files, so the users will be informed on server restarts. # schema files, so the users will be informed on server restarts.
SCHEMA_VERSION = 55 SCHEMA_VERSION = 56
dir_path = os.path.abspath(os.path.dirname(__file__)) dir_path = os.path.abspath(os.path.dirname(__file__))

View File

@ -224,7 +224,7 @@ class RoomMemberWorkerStore(EventsWorkerStore):
results = [] results = []
if membership_list: if membership_list:
where_clause = "user_id = ? AND (%s) AND forgotten = 0" % ( where_clause = "user_id = ? AND (%s) AND forgotten = 0" % (
" OR ".join(["membership = ?" for _ in membership_list]), " OR ".join(["m.membership = ?" for _ in membership_list]),
) )
args = [user_id] args = [user_id]
@ -453,8 +453,8 @@ class RoomMemberWorkerStore(EventsWorkerStore):
sql = """ sql = """
SELECT state_key FROM current_state_events AS c SELECT state_key FROM current_state_events AS c
INNER JOIN room_memberships USING (event_id) INNER JOIN room_memberships AS m USING (event_id)
WHERE membership = 'join' WHERE m.membership = 'join'
AND type = 'm.room.member' AND type = 'm.room.member'
AND c.room_id = ? AND c.room_id = ?
AND state_key LIKE ? AND state_key LIKE ?

View File

@ -0,0 +1,19 @@
/* Copyright 2019 The Matrix.org Foundation C.I.C.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-- We add membership to current state so that we don't need to join against
-- room_memberships, which can be surprisingly costly (we do such queries
-- very frequently).
ALTER TABLE current_state_events ADD membership TEXT;

View File

@ -618,15 +618,15 @@ class UserDirectoryStore(StateDeltasStore, BackgroundUpdateStore):
sql = """ sql = """
SELECT room_id FROM ( SELECT room_id FROM (
SELECT c.room_id FROM current_state_events AS c SELECT c.room_id FROM current_state_events AS c
INNER JOIN room_memberships USING (event_id) INNER JOIN room_memberships AS m USING (event_id)
WHERE type = 'm.room.member' WHERE type = 'm.room.member'
AND membership = 'join' AND m.membership = 'join'
AND state_key = ? AND state_key = ?
) AS f1 INNER JOIN ( ) AS f1 INNER JOIN (
SELECT c.room_id FROM current_state_events AS c SELECT c.room_id FROM current_state_events AS c
INNER JOIN room_memberships USING (event_id) INNER JOIN room_memberships AS m USING (event_id)
WHERE type = 'm.room.member' WHERE type = 'm.room.member'
AND membership = 'join' AND m.membership = 'join'
AND state_key = ? AND state_key = ?
) f2 USING (room_id) ) f2 USING (room_id)
""" """