Opened 51 minutes ago
Last modified 34 minutes ago
#37237 new Cleanup/optimization
Slow SQL query with a large list of values
| Reported by: | Adam Sołtysik | Owned by: | |
|---|---|---|---|
| Component: | Database layer (models, ORM) | Version: | 6.0 |
| Severity: | Normal | Keywords: | performance |
| Cc: | Triage Stage: | Accepted | |
| Has patch: | no | Needs documentation: | no |
| Needs tests: | no | Patch needs improvement: | no |
| Easy pickings: | no | UI/UX: | no |
Description
When we call something like queryset.filter(id__in=large_list), the query runs several times slower than the same query executed manually, even if there are no rows returned.
Example (function added in tests/basic/tests.py, testing on Postgres):
def test_id_in(self): import time values = list(range(-100000, 0)) t = time.perf_counter() print(Article.objects.filter(id__in=values)) print(f'{(time.perf_counter() - t):.3f} s') t = time.perf_counter() with connection.cursor() as cursor: cursor.execute('SELECT * FROM basic_article WHERE id = ANY(%s)', [values]) print(cursor.fetchall()) print(f'{(time.perf_counter() - t):.3f} s')
Results (python runtests.py basic -k id_in):
<QuerySet []> 0.584 s [] 0.176 s
Note that I'm using ANY as recommended by psycopg, but the same happens with a manually constructed query with IN.
Another situation when this slowdown appears is removing a large number of items from a M2M relation.
Change History (2)
comment:1 by , 42 minutes ago
| Keywords: | performance added |
|---|---|
| Triage Stage: | Unreviewed → Accepted |
Thanks for the bench. I think we should tentatively accept this for investigation. I suggested opening a ticket for the issue of large collections of values when looking at another profile, but it might have gotten lost in the shuffle.. (My concern at the time with the PR was that we weren't optimizing the right thing, but I'm glad to look at a new approach.)