Skip to content

Conversation

@Demagalawrence
Copy link

…nc calls


return await cursor.fetchall()

msgs = await Message.objects.using(self.using).filter(expire__gt=now).all()
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will make an exception here and keep the handcrafted query because it's more efficient.

The query uses DELETE...RETURNING which deletes and returns the deleted result in one query.

The new query with django ORM makes two queries (SELECT and DELETE)

await conn.execute(
sql.SQL('TRUNCATE TABLE {table}').format(table=sql.Identifier(GROUP_CHANNEL_TABLE))
)
await Message.objects.using(self.using).adelete()
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will also keep the handcrafted query and execute both Truncate calls in one SQL statement.

This should save one roundtrip to the server

@rissson
Copy link
Contributor

rissson commented Oct 29, 2025

Just adding my 2c here, we recently re-implemented this library and we went with ORM queries as well in the first place, but they were significantly slower than have a dedication psycopg async connection, as with the ORM implementation you're constantly waiting on the main thread for queries.

This was just our experience though, YMMV.

@Demagalawrence
Copy link
Author

i have not understood!

@rissson
Copy link
Contributor

rissson commented Nov 3, 2025

The Django ORM async interface relies on asgiref.sync_to_async, for example: https://github.com/django/django/blob/05ba1a9228128614fb3c475f1c4bdf0160f44dba/django/db/models/query.py#L1412. From the Django doc (https://docs.djangoproject.com/en/5.2/topics/async/#sync-to-async):

The reason [thread_sensitive=True] is needed in Django is that many libraries, specifically database adapters, require that they are accessed in the same thread that they were created in. Also a lot of existing Django code assumes it all runs in the same thread, e.g. middleware adding things to a request for later use in views.

This means that the main Django thread (usually started by an asgi server), which is a blocking thread, will be waited on to perform database queries. Hence, you reduce the throughput of channels-postgres because you're limited by the availability of the connection from the main thread.

@danidee10
Copy link
Owner

I assumed it would be slightly slower due to the translation from ORM to SQL but I wasn't aware of sync_to_async was such a bottleneck. This is a blocker @Demagalawrence

I don't see how we can merge it if it causes a big drop in performance. In the meantime, I'll focus on building a benchmark so we have a clearer picture on the performance.

@rissson
Copy link
Contributor

rissson commented Nov 3, 2025

Yeah I'm sorry I don't have a number, it just felt slower. This is definitely a "feeling" assessment, but it makes sense.

@Demagalawrence
Copy link
Author

Thanks for clarifying — that makes sense. I understand ORM async may reduce throughput. I’ll wait for your benchmark results. hmmmm i have understood something too , thank you so much

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants