development

Django ORM에서 select_related와 prefetch_related의 차이점은 무엇입니까?

big-blog 2020. 4. 15. 11:09
반응형

Django ORM에서 select_related와 prefetch_related의 차이점은 무엇입니까?


Django Doc에서

select_related() 외래 키 관계를 "따라"쿼리 실행시 추가 관련 개체 데이터를 선택합니다.

prefetch_related() 각 관계에 대해 별도의 조회를 수행하고 Python에서 "결합"합니다.

"파이썬에 참여하는 것"이란 무엇을 의미합니까? 누군가가 예를 들어 설명 할 수 있습니까?

내 이해는 외래 키 관계에 사용 select_related; M2M 관계에는을 사용하십시오 prefetch_related. 이 올바른지?


당신의 이해는 대부분 정확합니다. 당신은 사용 select_related이 선택 될 거라고 객체가 단일 객체, 그래서 때 OneToOneFieldForeignKey. 당신 은 당신이 언급 한 것과 반대로 prefetch_related"집합"을 얻을 때 사용 합니다 . "reverse s"의 의미를 명확히하기 위해 여기에 예가 있습니다.ManyToManyFieldForeignKeyForeignKey

class ModelA(models.Model):
    pass

class ModelB(models.Model):
    a = ForeignKey(ModelA)

ModelB.objects.select_related('a').all() # Forward ForeignKey relationship
ModelA.objects.prefetch_related('modelb_set').all() # Reverse ForeignKey relationship

차이점은 select_relatedSQL 조인을 수행하므로 SQL 서버에서 테이블의 일부로 결과를 다시 가져옵니다. prefetch_related반면에 다른 쿼리를 실행하므로 원래 개체의 중복 열이 줄어 듭니다 ( ModelA위 예에서). 사용할 prefetch_related수있는 모든 것에 사용할 수 있습니다 select_related.

트레이드 오프는 prefetch_related서버로 다시 선택하기 위해 ID 목록을 작성하여 보내야 한다는 점입니다. 시간이 오래 걸릴 수 있습니다. 거래 에서이 작업을 수행하는 좋은 방법이 있는지 확실하지 않지만 Django는 항상 목록을 보내고 SELECT ... WHERE pk IN (..., ..., ...)라고 말합니다. 원래. 이 경우 프리 페치 된 데이터가 드문 경우 (사람의 주소에 연결된 미국 주 개체라고하자)이 방법은 매우 좋지만 일대일에 가까울 경우 많은 통신이 낭비 될 수 있습니다. 의심스러운 경우 두 가지를 모두 시도하고 어느 것이 더 나은지 확인하십시오.

위에서 설명한 모든 것은 기본적으로 데이터베이스와의 통신에 관한 것입니다. 그러나 파이썬 측에서는 prefetch_related단일 객체를 사용하여 데이터베이스의 각 객체를 나타내는 추가 이점이 있습니다. select_related중복 된 개체가 각 "부모"개체에 대한 파이썬으로 작성됩니다. 파이썬의 객체는 상당한 메모리 오버 헤드를 가지고 있기 때문에 고려할 수도 있습니다.


두 가지 방법 모두 동일한 목적을 달성하여 불필요한 DB 쿼리를 방지합니다. 그러나 그들은 효율성을 위해 다른 접근법을 사용합니다.

이러한 방법 중 하나를 사용하는 유일한 이유는 하나의 큰 쿼리가 많은 작은 쿼리보다 선호되는 경우입니다. Django는 큰 쿼리를 사용하여 데이터베이스에 대해 주문형 쿼리를 수행하지 않고 메모리에 모델을 선제 적으로 만듭니다.

select_related각 조회마다 조인을 수행하지만 모든 조인 된 테이블의 열을 포함하도록 선택을 확장합니다. 그러나이 방법에는주의가 필요합니다.

조인은 쿼리의 행 수를 곱할 수 있습니다. 외래 키 또는 일대일 필드에 대해 조인을 수행하면 행 수가 증가하지 않습니다. 그러나 다 대다 조인에는이 보장이 없습니다. 따라서 Django select_related는 예기치 않게 큰 조인을 초래하지 않는 관계로 제한 됩니다.

"파이썬에 참여" 에 대한이 prefetch_related더 다음이 있어야 할 놀라운 조금. 결합 할 각 테이블에 대해 별도의 쿼리를 작성합니다. 다음과 같이 WHERE IN 절을 사용하여 이러한 각 테이블을 필터링합니다.

SELECT "credential"."id",
       "credential"."uuid",
       "credential"."identity_id"
FROM   "credential"
WHERE  "credential"."identity_id" IN
    (84706, 48746, 871441, 84713, 76492, 84621, 51472);

잠재적으로 너무 많은 행으로 단일 조인을 수행하는 대신 각 테이블이 별도의 쿼리로 분할됩니다.

참고 URL : https://stackoverflow.com/questions/31237042/whats-the-difference-between-select-related-and-prefetch-related-in-django-orm

반응형