666개의 Django 프로젝트가 비효율적인 데이터베이스 조회를 검사했습니다.절반이 넘는 사람들이 이 네 가지 반모드를 가지고 있어요.
9958 단어 djangopythonwebdevperformance
Django Doctor 정적 분석을 수행하여 이러한 문제를 검색하고 자동으로 해결합니다.우리는 666개의 Django 코드 라이브러리를 검사했는데 저효율의 Django ORM 호출을 발견했고 문제의 심각성에 놀랐다. 우리가 검사한 모든 Django 코드 라이브러리의 50%는 다음과 같은 반모드를 가지고 있다.
queryset.count() > 0
대신 queryset.exists()
사용len(queryset)
아님queryset.count()
if queryset:
가 아니라if queryset.exists():
이러한 성능 역모드를 어떻게 해결하시겠습니까?해봐our Django performance refactor challenge.
검사된 Django github 저장소의 절반 이상이 이러한 문제를 안고 있는 것을 감안하면 저장소 중 최소한 하나의 문제가 있을 수 있습니다.경험이 풍부한 Django 개발자는 이런 실수를 범하지 않을 것이라고 생각할 수 있지만 문제는 개발자가 외딴 섬이 아니라는 것이다. 시간이 지날수록 개발자는 팀을 바꾸고 기술 채무를 축적한 갈색 코드 라이브러리를 계승하며 초보 개발자가 작성한 코드를 심사한다.따라서 중요한 것은 다음과 같습니다.
사용하다.count () > 0 이 아닙니다.존재()
비교
queryset.count()
의 효율은 검사queryset.exists()
보다 낮다.Django docs 계수만 있으면 사용하고queryset.count()
, 최소한 하나의 결과가 존재하는지 알고 싶으면 사용하라queryset.exists()
.왜냐하면
queryset.count()
데이터베이스 테이블의 각 행을 검색하여 합계를 계산하는 SQL 작업이 수행됩니다.다른 한편 queryset.exists()
는 the most optimized way의 레코드 하나만 읽습니다.select_related
과 distinct
제거그래서
def check_hounds():
queryset = HoundsModel.objects.all()
if queryset.count() > 0:
return "oh no. Run!"
Django Doctor에서 이 문제를 자동으로 해결합니다.def check_hounds():
queryset = HoundsModel.objects.all()
if queryset.exists():
return "oh no. Run!"
Read more queryset 대신 len(queryset)을 사용합니다.개수()
len(queryset)
애플리케이션 레벨에서 실행되는 횟수입니다.이것은doingqueryset.count()
보다 효율이 훨씬 낮고 후자는 데이터베이스 단계에서 계산하고 계수만 되돌려준다.조회 집합은 lazily evaluated 이다. 이것은 코드와 데이터가 상호작용하기 전에 데이터베이스에서 기록을 읽지 않는다는 것을 의미한다.이것이 바로 우리가 데이터베이스에서 모든 기록을 다운로드하지 않아도 되는 이유이다
queryset.all()
.데이터와 상호작용하는 예는doing
len(queryset)
이다.이것은queryset의 모든 기록을 읽을 것입니다: 인터넷을 통해 데이터베이스를 효과적으로 다운로드합니다.효율이 특별히 높지 않다.한편, Doing
queryset.count()
은 SQLSELECT COUNT(*) FROM table
과 유사한 SQL을 실행하여 데이터베이스 단계의 계산을 처리한다.이것은 queryset.count()
를 사용하면 코드를 더욱 빠르고 데이터베이스 성능을 향상시킬 수 있다는 것을 의미한다.또 5000개의 기록을 다운로드하는 것은 길이를 확인하고 마지막에 버리기 위한 것이 얼마나 낭비인지 생각해 보자.그래서
def check_hounds():
queryset = HoundsModel.objects.all()
if len(queryset) > 2:
return "oh no. Run!"
Django Doctor에서 이 문제를 자동으로 해결합니다.def check_hounds():
if HoundsModel.objects.count() > 2:
return "oh no. Run!"
그럼에도 불구하고 길이를 검사한 후 기록을 읽어야 한다면 len(queryset)
유효할 수 있습니다.Read more
if-queryset 사용하기:if-queryset이 아닙니다.존재():
위와 유사하게 데이터베이스 테이블의 모든 줄을 메모리에 불러올 수 있습니다. 왜냐하면 조회 집합은 계산을 거쳤기 때문입니다.조회 집합의 진실/오류 여부를 검사하는 효율은 검사
queryset.exists()
보다 훨씬 낮다.만약 표가 매우 크면 효율이 특히 떨어진다. 그것은 데이터베이스에 있는 CPU의 최고치를 초래하고 웹 서버의 대량의 메모리를 차지할 수 있다.따라서 테이블에서 줄을 추출하지 않고 검사
queryset.exists()
합니다. 테이블에서 기록을 아주 효과적으로 읽으려고 시도할 뿐입니다.그래서
def check_hounds():
queryset = HoundsModel.objects.all()
if queryset:
return "oh no. Run!"
Django Doctor에서 이 문제를 자동으로 해결합니다.def check_hounds():
queryset = HoundsModel.objects.all()
if queryset.exists():
return "oh no. Run!"
Read more 외키를 직접 사용하지 마라
외부 키를 사용할 때 방문
model_instance.related_field.id
은 계산related_field.id
에서 데이터베이스를 읽게 됩니다.이것은 Domodel_instance.related_field_id
를 통해 제거할 수 있다. 이것은 Django가 이미 대상에 캐시한 키 값으로 이 장면의 효율을 높일 수 있다.그래서
def check_hounds(pk, farm_ids):
hound = HoundsModel.objects.get(pk=pk)
if hound.farm.id in farm_ids:
...
Django Doctor에서 이 문제를 자동으로 해결합니다.def check_hounds(pk, farm_ids):
hound = HoundsModel.objects.get(pk=pk)
if hound.farm_id in farm_ids:
...
Read more Django 코드에는 이러한 역모드가 있습니까?
시간의 추이에 따라 과학 기술 채무는 너의 코드 라이브러리에 쉽게 빠져들게 된다.django.doctor 또는 review your GitHub PRs를 통해 확인할 수 있습니다.
아니면 해봐Django refactor challenges.
Reference
이 문제에 관하여(666개의 Django 프로젝트가 비효율적인 데이터베이스 조회를 검사했습니다.절반이 넘는 사람들이 이 네 가지 반모드를 가지고 있어요.), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/codereviewdoctor/666-django-projects-checked-for-inefficient-database-queries-over-half-had-these-4-anti-patterns-4383텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)