mirror of
https://github.com/zulip/zulip.git
synced 2025-11-04 14:03:30 +00:00
The database can do this faster than we can, and it reduces the amount of information transmitted over the wire.
66 lines
1.8 KiB
Python
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])
|