장고 쿼리 집합의 카운트() 대 len()
장고에서 제가 지금.QuerySet
결과를 반복하여 인쇄할 예정인데 개체 수를 세는 데 가장 적합한 옵션은 무엇입니까?len(qs)
아니면qs.count()
?
(또한 동일한 반복에서 개체 수를 세는 것은 선택 사항이 아닙니다.)
장고 문서에서는 다음을 사용할 것을 권장합니다.count
보다는len
:
참고: 사용 안 함
len()
QuerySets에서 세트의 레코드 수를 결정하는 것만 원하는 경우.SQL을 사용하여 데이터베이스 수준에서 카운트를 처리하는 것이 훨씬 효율적입니다.SELECT COUNT(*)
, 그리고 장고는 제공합니다.count()
바로 이런 이유로 방법을 사용합니다.
어차피 이 QuerySet을 반복하는 것이므로 (사용하지 않는 한) 결과가 캐시되므로 사용하는 것이 좋습니다.len
, 이렇게 하면 데이터베이스에 다시 타격을 주지 않을 뿐만 아니라 다른 수의 결과를 가져올 가능성도 있기 때문입니다!)
사용하시는 경우iterator
, 그런 다음 같은 이유로 카운트를 사용하는 대신 반복할 때 카운트 변수를 포함하는 것을 제안합니다.
둘중에len()
그리고.count()
상황에 따라 다르며 이를 올바르게 사용하기 위해 어떻게 작동하는지 깊이 이해할 필요가 있습니다.
몇 가지 시나리오를 알려드리겠습니다.
- (가장 중요한)요소의 개수만 알고 싶을 뿐 어떤 방식으로도 요소를 처리할 계획이 없는 경우 사용하는 것이 중요합니다.
count()
:
작업관리: queryset.count()
- 싱글로 실행됩니다.SELECT COUNT(*) FROM some_table
쿼리, 모든 계산은 RDBMS 쪽에서 수행되며, 파이썬은 O(1)의 고정 비용으로 결과 번호만 검색하면 됩니다.
하지 않음: len(queryset)
- 이것은 잘 될 것입니다.SELECT * FROM some_table
쿼리, 전체 테이블 O(N)을 가져오고 저장을 위해 추가 O(N) 메모리가 필요합니다.이건 최악의 상황입니다.
- 어쨌든 쿼리 세트를 가져오려면 사용하는 것이 좋습니다.
len()
추가적인 데이터베이스 쿼리를 발생시키지 않을 것입니다.count()
그럴 것이다
len()
(한 db 쿼리)
len(queryset) # SELECT * 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
count()
(두 개의 DB 쿼리!)
queryset.count() # First db query SELECT COUNT(*)
for obj in queryset: # Second db query (fetching data) SELECT *
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)
장고 문서의 참고 자료:
제가 생각하기에.len(qs)
결과를 반복해야 하므로 여기서 더 합리적입니다.qs.count()
원하는 모든 것이 카운트를 인쇄하고 결과를 반복하지 않는 것이 더 나은 옵션입니다.
len(qs)
에할다다e할tl에hee를select * from table
반면에qs.count()
와 함께 db에 도달할 것입니다.select count(*) from table
.
.qs.count()
하며 이를 할 수 .고할수다환다수를lt할고tret .
테스트 측정(Postresql)을 선호하는 사람의 경우:
간단한 사용자 모델과 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()
.
하지만
예를 들어, 메모리 제한이 있는 경우, 레코드를 통해 수행되는 작업을 분할하는 것이 편리할 수 있습니다.그것은 장고 페이지를 이용하여 달성할 수 있습니다.
에 을 count()
를 선택할 수 있으므로 전체 쿼리 세트를 한 번에 가져올 필요가 없습니다.
모델 및 원시 쿼리가 카운트()와 len()을 사용하여 1000만 행을 얼마나 빨리 얻을 수 있는지 실험했습니다.*Postgre를 사용하였습니다.SQL 입니다.
<실험 결과>
셈을 보다 | len () | |
---|---|---|
모델조회 | 1.02초 | 46초13 |
원시 쿼리 | 0.48초 | 3.16초 |
따라서 빠른 속도의 순서는 아래와 같습니다.
count()
원시 쿼리(0.48초)를 사용합니다.count()
모델 쿼리 포함(1.02초)len()
원시 쿼리(3.16초)를 사용합니다.len()
모델 쿼리 포함(46.13초)
는 기본적으로 합니다를 사용하는 합니다.count()
합니다. 모델 는다기델에기다h는tley를n .len()
, 원시 쿼리보다 코드가 적고 편리하지만 select_for_update를 사용할 때는 사용해야 합니다.len()
. 왜냐하면델와께께와델hhey .select_for_update()
와 함께count()
작동하지 않으며 원시 쿼리보다 코드가 적고 편리합니다.
<실험방법>
먼저 열만 있는 모델을 만들었습니다.
# "store/models.py"
from django.db import models
class Test(models.Model):
pass
그런 다음 아래 명령을 실행합니다.
python manage.py makemigrations && python manage.py migrate
그런 다음 psql로 테이블에 1000만 행을 한 번에 삽입합니다.
postgres=# INSERT INTO store_test (id) SELECT generate_series(1, 10000000);
INSERT 0 10000000
Time: 29929.337 ms (00:29.929)
마지막으로 뛰었습니다.test_view()
아래와 같이
# "store/views.py"
from time import time
from .models import Test
from django.db import connection
from django.http import HttpResponse
def test_view(request):
# "count()" with model query
start = time()
print(Test.objects.all().count(), "- count() - Model query")
end = time()
print(round(end - start, 2), "seconds\n")
# "len()" with model query
start = time()
print(len(Test.objects.all()), "- len() - Model query")
end = time()
print(round(end - start, 2), "seconds\n")
# "count()" with raw query
start = time()
with connection.cursor() as cursor:
cursor.execute("SELECT count(*) FROM store_test;")
print(cursor.fetchone()[0], "- count() - Raw query")
end = time()
print(round(end - start, 2), "seconds\n")
# "len()" with raw query
start = time()
with connection.cursor() as cursor:
cursor.execute("SELECT * FROM store_test;")
print(len(cursor.fetchall()), "- len() - Raw query")
end = time()
print(round(end - start, 2), "seconds\n")
return HttpResponse("Test_view")
콘솔의 출력:
10000000 - count() - Model query
1.02 seconds
10000000 - len() - Model query
46.13 seconds
10000000 - count() - Raw query
0.48 seconds
10000000 - len() - Raw query
3.16 seconds
[18/Dec/2022 07:12:14] "GET /store/test_view/ HTTP/1.1" 200 9
언급URL : https://stackoverflow.com/questions/14327036/count-vs-len-on-a-django-queryset
'programing' 카테고리의 다른 글
우커머스 체크아웃에서 기본값을 설정하는 방법 (0) | 2023.09.16 |
---|---|
혼합 환경에서의 MariaDB와 MySQL - 마스터/슬레이브 설계의 복제 문제 (0) | 2023.09.16 |
mariadb 10.0 이후 jdbc 통신 링크 오류 (0) | 2023.09.16 |
Woocommerce 3에서 모든 배송 클래스 받기 (0) | 2023.09.16 |
WordPress: WP_Query를 사용자 지정 날짜 필드별로 주문하고 매달 이후에 루프를 분할합니다. (0) | 2023.09.16 |