실전 Django의 모델 조작의prefetchrelated () 조회의 최적화 (2)

이 시리즈의 두 번째 편입니다. 내용은prefetch 입니다.related () 함수의 용도, 실현 경로, 사용 방법
여기
1편은 여기서 예와 select 을 강의합니다.related()
제3편은 여기서 몇 가지 실례를 이용하여 복잡한 조회의 최적 실천을 설명한다
3. prefetch_related()
prefetchrelated ()로 최적화합니다.혹시 One Tomany Field라는 게 하나도 없다고 말할지도 몰라요.실제로 ForeignKey는 다대일 필드이고 ForeignKey와 관련된 필드는 다대일 필드입니다.
작용과 방법
prefetch_related() 및 selectrelated()의 디자인 목적은 매우 비슷하다. 모두 SQL 조회의 수를 줄이기 위한 것이지만 실현 방식은 다르다.후자는 JOIN 문을 통해 SQL 쿼리 내에서 문제를 해결합니다.그러나 다대다 관계에 대해 SQL 문구를 사용하여 해결하는 것은 현명하지 않다. JOIN이 얻은 표가 길기 때문에 SQL 문구의 운행 시간이 증가하고 메모리가 차지하는 시간이 증가하기 때문이다.n개의 객체가 있는 경우 각 객체의 여러 쌍 다중 필드가 Mi 막대에 해당합니다.Σ(n) Mi 행의 결과 테이블.
prefetch_related () 의 해결 방법은 각각의 표를 조회한 다음 파이톤으로 그들 사이의 관계를 처리하는 것이다.계속해서 상기 예시를 설명하자면, 만약에 우리가 장삼이 가 본 모든 도시를 얻으려면prefetchrelated () 는 다음과 같이 해야 합니다.

   
   
   
   
  1. >>> zhangs = Person.objects.prefetch_related( 'visitation').get(firstname= u" ",lastname= u" ")
  2. >>> for city in zhangs.visitation.all() :
  3. ... print city
  4. ...
SQL :

   
   
   
   
  1. SELECT `QSOptimize_person`. `id`, `QSOptimize_person`. `firstname`,
  2. `QSOptimize_person`. `lastname`, `QSOptimize_person`. `hometown_id`, `QSOptimize_person`. `living_id`
  3. FROM `QSOptimize_person`
  4. WHERE ( `QSOptimize_person`. `lastname` = ' ' AND `QSOptimize_person`. `firstname` = ' ');
  5. SELECT ( `QSOptimize_person_visitation`. `person_id`) AS `_prefetch_related_val`, `QSOptimize_city`. `id`,
  6. `QSOptimize_city`. `name`, `QSOptimize_city`. `province_id`
  7. FROM `QSOptimize_city`
  8. INNER JOIN `QSOptimize_person_visitation` ON ( `QSOptimize_city`. `id` = `QSOptimize_person_visitation`. `city_id`)
  9. WHERE `QSOptimize_person_visitation`. `person_id` IN ( 1);

SQL Person , , `QSOptimize_person_visitation` `person_id` , `city` (INNER JOIN ) 。

+----+-----------+----------+-------------+-----------+
| id | firstname | lastname | hometown_id | living_id |
+----+-----------+----------+-------------+-----------+
| 1 |          |   |           3 | 1 |
+----+-----------+----------+-------------+-----------+
1 row in set (0.00 sec)

±----------------------±—±----------±------------+
| _prefetch_related_val | id | name | province_id |
±----------------------±—±----------±------------+
|
1 | 1 | | 1 |
| 1 | 2 | | 2 |
|
1 | 3 | | 1 |
±----------------------±—±----------±------------+
3 rows in set (0.00 sec) 、 、 。



, , :

>>> hb = Province.objects.prefetch_related('city_set').get(name__iexact=u"   ")
>>> for city in hb.city_set.all():
...   city.name
...
 
  

SQL :

SELECT `QSOptimize_province`.`id`, `QSOptimize_province`.`name` 
FROM `QSOptimize_province` 
WHERE `QSOptimize_province`.`name` LIKE '   ' ;

SELECT QSOptimize_city . id , QSOptimize_city . name , QSOptimize_city . province_id FROM QSOptimize_city WHERE QSOptimize_city . province_id IN (1); 획득한 표:

+----±----------+
| id | name |
+----±----------+
| 1 | |
+----±----------+
1 row in set (0.00 sec)

+----±----------±------------+ | id | name | province_id | +--±------------±--------------------+| 1 | 우한시| 1 | 3 | 텐언시| 1 | +------------------------------+2 rows in set(0.00sec)
우리는 prefetch가 사용하는 것이 IN 문장으로 이루어진 것을 볼 수 있다.이렇게 하면QuerySet에 있는 대상의 수가 너무 많을 때 데이터베이스 특성에 따라 성능 문제가 발생할 수 있습니다.
사용법
*lookups 매개 변수
prefetch_related () 는 Django < 1.7 에서 이 방법만 사용합니다.및 selectrelated () 와 같이prefetchrelated () 도 깊이 있는 검색을 지원합니다. 예를 들어 장씨 성을 가진 모든 사람이 갔던 성을 얻으려면:

   
   
   
   
  1. >>> zhangs = Person.objects.prefetch_related( 'visitation__province').filter(firstname__iexact= u' ')
  2. >>> for i in zhangs:
  3. ... for city in i.visitation.all():
  4. ... print city.province
  5. ...
SQL:

   
   
   
   
  1. SELECT `QSOptimize_person`. `id`, `QSOptimize_person`. `firstname`,
  2. `QSOptimize_person`. `lastname`, `QSOptimize_person`. `hometown_id`, `QSOptimize_person`. `living_id`
  3. FROM `QSOptimize_person`
  4. WHERE `QSOptimize_person`. `firstname` LIKE ' ' ;
  5. SELECT ( `QSOptimize_person_visitation`. `person_id`) AS `_prefetch_related_val`, `QSOptimize_city`. `id`,
  6. `QSOptimize_city`. `name`, `QSOptimize_city`. `province_id` FROM `QSOptimize_city`
  7. INNER JOIN `QSOptimize_person_visitation` ON ( `QSOptimize_city`. `id` = `QSOptimize_person_visitation`. `city_id`)
  8. WHERE `QSOptimize_person_visitation`. `person_id` IN ( 1, 4);
  9. SELECT `QSOptimize_province`. `id`, `QSOptimize_province`. `name`
  10. FROM `QSOptimize_province`
  11. WHERE `QSOptimize_province`. `id` IN ( 1, 2);
+----+-----------+----------+-------------+-----------+
| id | firstname | lastname | hometown_id | living_id |
+----+-----------+----------+-------------+-----------+
| 1 |          |   |           3 | 1 |
| 4 |          |   |           2 | 2 |
+----+-----------+----------+-------------+-----------+
2 rows in set (0.00 sec)

±----------------------±—±----------±------------+
| _prefetch_related_val | id | name | province_id |
±----------------------±—±----------±------------+
|
1 | 1 | | 1 |
| 1 | 2 | | 2 |
|
4 | 2 | | 2 |
| 1 | 3 | | 1 |
±----------------------±—±----------±------------+
4 rows in set (0.00 sec)

±—±----------+
| id | name |
±—±----------+
| 1 | |
|
2 | |
±—±----------+
2 rows in set (0.00 sec)


, prefetch_related , 1.7 select_related 。


, QuerySet , , prefetch_related 。 Django , 。 filter()、exclude() SQL 。 all() , 。

, “ ” , SQL :


   
   
   
   
  1. plist = Person.objects.prefetch_related( 'visitation')
  2. [p.visitation.filter(name__icontains= u" ") for p in plist]
4 , 2+4 SQL :

   
   
   
   
  1. SELECT `QSOptimize_person`. `id`, `QSOptimize_person`. `firstname`, `QSOptimize_person`. `lastname`,
  2. `QSOptimize_person`. `hometown_id`, `QSOptimize_person`. `living_id`
  3. FROM `QSOptimize_person`;
  4. SELECT ( `QSOptimize_person_visitation`. `person_id`) AS `_prefetch_related_val`, `QSOptimize_city`. `id`,
  5. `QSOptimize_city`. `name`, `QSOptimize_city`. `province_id`
  6. FROM `QSOptimize_city`
  7. INNER JOIN `QSOptimize_person_visitation` ON ( `QSOptimize_city`. `id` = `QSOptimize_person_visitation`. `city_id`)
  8. WHERE `QSOptimize_person_visitation`. `person_id` IN ( 1, 2, 3, 4);
  9. SELECT `QSOptimize_city`. `id`, `QSOptimize_city`. `name`, `QSOptimize_city`. `province_id`
  10. FROM `QSOptimize_city`
  11. INNER JOIN `QSOptimize_person_visitation` ON ( `QSOptimize_city`. `id` = `QSOptimize_person_visitation`. `city_id`)
  12. WHERE( `QSOptimize_person_visitation`. `person_id` = 1 AND `QSOptimize_city`. `name` LIKE '% %' );
  13. SELECT `QSOptimize_city`. `id`, `QSOptimize_city`. `name`, `QSOptimize_city`. `province_id`
  14. FROM `QSOptimize_city`
  15. INNER JOIN `QSOptimize_person_visitation` ON ( `QSOptimize_city`. `id` = `QSOptimize_person_visitation`. `city_id`)
  16. WHERE ( `QSOptimize_person_visitation`. `person_id` = 2 AND `QSOptimize_city`. `name` LIKE '% %' );
  17. SELECT `QSOptimize_city`. `id`, `QSOptimize_city`. `name`, `QSOptimize_city`. `province_id`
  18. FROM `QSOptimize_city`
  19. INNER JOIN `QSOptimize_person_visitation` ON ( `QSOptimize_city`. `id` = `QSOptimize_person_visitation`. `city_id`)
  20. WHERE ( `QSOptimize_person_visitation`. `person_id` = 3 AND `QSOptimize_city`. `name` LIKE '% %' );
  21. SELECT `QSOptimize_city`. `id`, `QSOptimize_city`. `name`, `QSOptimize_city`. `province_id`
  22. FROM `QSOptimize_city`
  23. INNER JOIN `QSOptimize_person_visitation` ON ( `QSOptimize_city`. `id` = `QSOptimize_person_visitation`. `city_id`)
  24. WHERE ( `QSOptimize_person_visitation`. `person_id` = 4 AND `QSOptimize_city`. `name` LIKE '% %' );


,QuerySet lazy , 。 Python ,for plist iterator, 。 SQL prefetch_related 。

city , Person.visitation filter , 。 , SQL 。


? Django >= 1.7, Prefetch , Django < 1.7, Python 。


   
   
   
   
  1. plist = Person.objects.prefetch_related( 'visitation')
  2. [[city for city in p.visitation.all() if u" " in city.name] for p in plist]


Prefetch

Django >= 1.7, Prefetch prefetch_related 。

: 1.7 Django , Django , 。


Prefetch :

  1. Prefetch prefetch 。
  2. Prefetch prefetch_related , 。
  3. queryset prefetch QuerySet。
  4. to_attr prefetch 。
  5. Prefetch lookups 。

, “ ” “ ” :


   
   
   
   
  1. wus = City.objects.filter(name__icontains = u" ")
  2. zhous = City.objects.filter(name__icontains = u" ")
  3. plist = Person.objects.prefetch_related(
  4. Prefetch( 'visitation', queryset = wus, to_attr = "wu_city"),
  5. Prefetch( 'visitation', queryset = zhous, to_attr = "zhou_city"),)
  6. [p.wu_city for p in plist]
  7. [p.zhou_city for p in plist]

: , 。


,Prefetch 。

None

None prefetch_related。 :

>>> prefetch_cleared_qset = qset.prefetch_related(None)
   
   
   
   


  1. prefetch_related 。
  2. prefetch_related , Python 。
  3. select_related 。 select_related 。
  4. Django >= 1.7 Prefetch , Django 。
  5. prefetch_related ,Prefetch 。
  6. prefetch_related prefetch , , 。
  7. None prefetch_related。



좋은 웹페이지 즐겨찾기