[python] Django QuerySet의 개수 대 len
장고에서 QuerySet
반복하고 결과를 인쇄 할 것이 있다는 점을 감안할 때 개체를 계산하는 가장 좋은 옵션은 무엇입니까? len(qs)
또는 qs.count()
?
(또한 동일한 반복에서 객체를 계산하는 것은 옵션이 아닙니다.)
답변
하지만 장고 워드 프로세서 사용을 권장 count
하기보다는 len
:
참고 :
len()
집합의 레코드 수를 확인하기 만하면되는 경우 QuerySets에서 사용하지 마십시오 . SQL을 사용하여 데이터베이스 수준에서 카운트를 처리하는 것이 훨씬 더 효율적SELECT COUNT(*)
이며 Django는count()
정확하게 이러한 이유로 메서드를 제공합니다 .
어쨌든이 검색어 세트를 반복하고 있기 때문에, 결과는 캐시됩니다 (당신이 사용하지 않는 경우 iterator
), 그리고 그것을 사용하는 것이 바람직 할 수 있도록 len
하기 때문에, 이 피합니다이 가능 결과 다른 번호를 검색 또한 데이터베이스를 다시 타격, 그리고 !) .
을 사용하는 경우 iterator
동일한 이유로 (count를 사용하는 대신) 반복 할 때 계수 변수를 포함하는 것이 좋습니다.
답변
len()
및 중 선택 count()
하는 것은 상황에 따라 다르며 올바르게 사용하기 위해 작동하는 방식을 깊이 이해하는 것이 좋습니다.
몇 가지 시나리오를 제공하겠습니다.
-
(가장 중요) 요소 수만 알고 싶고 어떤 식 으로든 처리 할 계획이없는 경우
count()
다음 을 사용하는 것이 중요합니다 .DO :
queryset.count()
-이것은 단일SELECT COUNT(*) some_table
쿼리 를 수행 합니다. 모든 계산은 RDBMS 측에서 수행됩니다. Python은 고정 비용이 O (1) 인 결과 번호를 검색하면됩니다.하지 말아야 할 사항 :
len(queryset)
–SELECT * FROM some_table
쿼리 를 수행하고 전체 테이블 O (N)을 가져오고이를 저장하기 위해 추가 O (N) 메모리가 필요합니다. 할 수있는 최악의 상황 -
어쨌든
len()
쿼리 세트 를 가져 오려는 경우 추가 데이터베이스 쿼리가 발생하지 않는 사용 하는 것이 약간 더 좋습니다count()
.len(queryset) # fetching all the data - NO extra cost - data would be fetched anyway in the for loop for obj in queryset: # data is already fetched by len() - using cache pass
카운트:
queryset.count() # this will perform an extra db query - len() did not for obj in queryset: # fetching data pass
-
두 번째 경우 되돌림 (쿼리 세트를 이미 가져온 경우) :
for obj in queryset: # iteration fetches the data len(queryset) # using already cached data - O(1) no extra cost queryset.count() # using cache - O(1) no extra db query len(queryset) # the same O(1) queryset.count() # the same: no query, O(1)
“내부”를 살펴보면 모든 것이 명확 해집니다.
class QuerySet(object):
def __init__(self, model=None, query=None, using=None, hints=None):
# (...)
self._result_cache = None
def __len__(self):
self._fetch_all()
return len(self._result_cache)
def _fetch_all(self):
if self._result_cache is None:
self._result_cache = list(self.iterator())
if self._prefetch_related_lookups and not self._prefetch_done:
self._prefetch_related_objects()
def count(self):
if self._result_cache is not None:
return len(self._result_cache)
return self.query.get_count(using=self.db)
Django 문서의 좋은 참조 :
답변
len(qs)
결과를 반복해야하므로 여기서 사용하는 것이 더 합리적 이라고 생각 합니다. qs.count()
원하는 모든 작업이 결과를 반복하지 않고 개수를 인쇄하는 경우 더 나은 옵션입니다.
len(qs)
는 데이터베이스를 치는 select * from table
반면 .qs.count()
select count(*) from table
또한 qs.count()
반환 정수를 제공하고 반복 할 수 없습니다.
답변
테스트 측정 (Postresql)을 선호하는 사람들을 위해 :
간단한 Person 모델과 1000 개의 인스턴스가있는 경우 :
class Person(models.Model):
name = models.CharField(max_length=100)
age = models.SmallIntegerField()
def __str__(self):
return self.name
평균적으로 다음을 제공합니다.
In [1]: persons = Person.objects.all()
In [2]: %timeit len(persons)
325 ns ± 3.09 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
In [3]: %timeit persons.count()
170 ns ± 0.572 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)
따라서이 특정 테스트 사례 보다 count()
거의 2 배 더 빠르게 볼 수있는 방법은 무엇 입니까len()
?
답변
다른 사람들이 이미 답변 한 내용 요약 :
len()
모든 레코드를 가져 와서 반복합니다.count()
SQL COUNT 작업을 수행합니다 (큰 쿼리 집합을 처리 할 때 훨씬 빠름).
또한이 작업 후에 전체 쿼리 세트가 반복되는 경우 전체적으로를 사용하는 것이 약간 더 효율적일 수 있습니다 len()
.
하나
일부 경우, 예를 들어 메모리 제한이있는 경우 레코드에 대해 수행 된 작업을 분할하는 것이 편리 할 수 있습니다 (가능한 경우). 그것은 django pagination을 사용하여 얻을 수 있습니다 .
그런 다음 사용 count()
을 선택하면 전체 쿼리 세트를 한 번에 가져 오지 않아도됩니다.