zulip/zerver/lib/user_message.py

66 lines
1.8 KiB
Python

from typing import List
from django.db import connection
from psycopg2.extras import execute_values
from psycopg2.sql import SQL
from zerver.models import UserMessage
class UserMessageLite:
"""
The Django ORM is too slow for bulk operations. This class
is optimized for the simple use case of inserting a bunch of
rows into zerver_usermessage.
"""
def __init__(self, user_profile_id: int, message_id: int, flags: int) -> None:
self.user_profile_id = user_profile_id
self.message_id = message_id
self.flags = flags
def flags_list(self) -> List[str]:
return UserMessage.flags_list_for_flags(self.flags)
def bulk_insert_ums(ums: List[UserMessageLite]) -> None:
"""
Doing bulk inserts this way is much faster than using Django,
since we don't have any ORM overhead. Profiling with 1000
users shows a speedup of 0.436 -> 0.027 seconds, so we're
talking about a 15x speedup.
"""
if not ums:
return
vals = [(um.user_profile_id, um.message_id, um.flags) for um in ums]
query = SQL(
"""
INSERT into
zerver_usermessage (user_profile_id, message_id, flags)
VALUES %s
ON CONFLICT DO NOTHING
"""
)
with connection.cursor() as cursor:
execute_values(cursor.cursor, query, vals)
def bulk_insert_all_ums(user_ids: List[int], message_ids: List[int], flags: int) -> None:
if not user_ids or not message_ids:
return
query = SQL(
"""
INSERT INTO zerver_usermessage (user_profile_id, message_id, flags)
SELECT user_profile_id, message_id, %s AS flags
FROM UNNEST(%s) user_profile_id
CROSS JOIN UNNEST(%s) message_id
ON CONFLICT DO NOTHING
"""
)
with connection.cursor() as cursor:
cursor.execute(query, [flags, user_ids, message_ids])