Это может зависеть от системы БД, поэтому прежде всего я должен отметить, что я использую PostgreSQL.
Следуя предложению blue_note, я посмотрел план выполнения запроса с .explain()
, и он был идентичен(за исключением порядка элементов) для списка, каждый элемент которого повторяется 4 раза, и для набора с такими же элементами. Это означает, что Django создает какой-то список для внутренней конвертации. Затем я использовал timeit
, чтобы увидеть, какой из двух подходов быстрее, и оказалось, что сначала преобразование списка в набор происходит быстрее. Вот мой код:
from timeit import timeit
qs = SomeModel.objects.all()
l = [str(x.id) for x in qs]
l.extend(l)
l.extend(l)
def t_l():
return SomeModel.objects.filter(id__in=l)
def t_s():
return SomeModel.objects.filter(id__in=set(l))
>>> SomeModel.objects.filter(id__in=l).explain()
"Bitmap Heap Scan on authentication_permissionsvatnumber (cost=9.26..19.48 rows=8 width=86)\n Recheck Cond: (id = ANY ('{824ea540-6fac-4929-b5cc-306890356ca1,349d3d2d-f8f8-45b7-9e80-538189b455e4,7d1bc4aa-9442-4fbc-a419-67f56483cd8c,8dd98c0e-e792-4b5c-80f6-c08de202b888,0dfddb54-19ae-4204-82a3-183ec01efb83,93c1fb80-b464-4651-b8c3-7928eaf56790,7d7aa210-1979-4f90-8680-a3dc7e685a71,6db11e75-6fae-421e-bda5-be22b1b2e82a}'::uuid[]))\n -> Bitmap Index Scan on authentication_permissionsvatnumber_pkey (cost=0.00..9.26 rows=8 width=0)\n Index Cond: (id = ANY ('{824ea540-6fac-4929-b5cc-306890356ca1,349d3d2d-f8f8-45b7-9e80-538189b455e4,7d1bc4aa-9442-4fbc-a419-67f56483cd8c,8dd98c0e-e792-4b5c-80f6-c08de202b888,0dfddb54-19ae-4204-82a3-183ec01efb83,93c1fb80-b464-4651-b8c3-7928eaf56790,7d7aa210-1979-4f90-8680-a3dc7e685a71,6db11e75-6fae-421e-bda5-be22b1b2e82a}'::uuid[]))"
>>> SomeModel.objects.filter(id__in=set(l)).explain()
"Bitmap Heap Scan on authentication_permissionsvatnumber (cost=9.26..19.48 rows=8 width=86)\n Recheck Cond: (id = ANY ('{0dfddb54-19ae-4204-82a3-183ec01efb83,8dd98c0e-e792-4b5c-80f6-c08de202b888,93c1fb80-b464-4651-b8c3-7928eaf56790,7d7aa210-1979-4f90-8680-a3dc7e685a71,6db11e75-6fae-421e-bda5-be22b1b2e82a,349d3d2d-f8f8-45b7-9e80-538189b455e4,7d1bc4aa-9442-4fbc-a419-67f56483cd8c,824ea540-6fac-4929-b5cc-306890356ca1}'::uuid[]))\n -> Bitmap Index Scan on authentication_permissionsvatnumber_pkey (cost=0.00..9.26 rows=8 width=0)\n Index Cond: (id = ANY ('{0dfddb54-19ae-4204-82a3-183ec01efb83,8dd98c0e-e792-4b5c-80f6-c08de202b888,93c1fb80-b464-4651-b8c3-7928eaf56790,7d7aa210-1979-4f90-8680-a3dc7e685a71,6db11e75-6fae-421e-bda5-be22b1b2e82a,349d3d2d-f8f8-45b7-9e80-538189b455e4,7d1bc4aa-9442-4fbc-a419-67f56483cd8c,824ea540-6fac-4929-b5cc-306890356ca1}'::uuid[]))"
>>> timeit(t_l, number=10000)
0.9831858319999967
>>> timeit(t_s, number=10000)
0.7851520270000023
Но я также хотел посмотреть, что происходит, когда список и набор уже имеют одинаковое количество уникальных элементов:
>>> timeit(t_l, number=10000)
0.8463515899999976
>>> timeit(t_s, number=10000)
0.7903294700000174
Как выясняется, преобразованиесписок для набора первым все еще быстрее, хотя и с гораздо меньшим запасом. Если бы я предположил, мне кажется, что Django всегда запускает какой-то список для внутренней конвертации перед отправкой запроса в БД.