#37237: Slow SQL query with a large list of values
-------------------------------------+-------------------------------------
Reporter: Adam Sołtysik | Owner: (none)
Type: | Status: new
Cleanup/optimization |
Component: Database layer | Version: 6.0
(models, ORM) |
Severity: Normal | Resolution:
Keywords: performance | Triage Stage: Accepted
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Comment (by Adam Sołtysik):
Indeed we're talking about the same thing, and performance is much better
with that PR applied. Nice to see it being worked on.
However, the manually executed query is still noticably faster. In my
benchmark, we get from 0.584 s to 0.235 s, which is ~1.3x slower than the
0.176 s.
That could be considered reasonable as an ORM abstraction cost, but a
bigger slowdown remains with M2M, which I also mentioned. Here's a
benchmark:
{{{#!python
def test_m2m_remove(self):
import time
values = list(range(-100000, 0))
article = Article.objects.create()
t = time.perf_counter()
article.publications.remove(*values)
# or (same time):
# Article.publications.through.objects.filter(article=article,
publication__in=values).delete()
print(f'{(time.perf_counter() - t):.3f} s')
t = time.perf_counter()
with connection.cursor() as cursor:
cursor.execute('''
DELETE FROM many_to_many_article_publications
WHERE article_id = %s AND publication_id = ANY(%s)
''', [
article.id, values])
print(f'{(time.perf_counter() - t):.3f} s')
}}}
Best results:
* 0.638 s for ORM on `main`
* 0.314 s for ORM with the PR
* 0.143 s for `cursor.execute`
So ~2.2x slower here, if I didn't miss anything.
On one hand, this discussion could be potentially continued in
https://github.com/django/django/pull/21605, but on the other hand, this
could be a different matter than the compilation to `ANY`, so maybe it's
worth keeping this issue separate?
--
Ticket URL: <
https://code.djangoproject.com/ticket/37237#comment:3>