В чем разница между select related и prefetch related в Django ORM?



в Django doc,




select_related() "следует" за отношениями внешнего ключа, выбирая дополнительные данные связанных объектов при выполнении запроса.



prefetch_related() выполняет отдельный поиск для каждого отношения и выполняет" присоединение " в Python.




что значит "делать присоединение в python"? Может кто-нибудь проиллюстрировать на примере?



Я понимаю, что для внешнего ключа отношения, используйте select_related; и для отношения М2М, используйте prefetch_related. Это правильно?

744   2  

2 ответов:

ваше понимание в основном правильно. Вы используете select_related когда объект, который вы собираетесь выбрать один объект, так OneToOneField или ForeignKey. Вы используете prefetch_related когда вы собираетесь получить "набор" вещей, так ManyToManyFields как вы сказали или наоборот ForeignKeys. просто чтобы уточнить, что я имею в виду под "обратным ForeignKeys " Вот пример:

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_related выполняет SQL-соединение и поэтому возвращает результаты как часть таблицы с SQL-сервера. prefetch_related С другой стороны выполняет другой запрос и, следовательно, уменьшает избыточные столбцы в исходном объекте (ModelA в приведенном выше примере). Вы можете использовать prefetch_related за все, что вы можете использовать select_related for.

компромиссы заключаются в том, что prefetch_related должен создать и отправить список идентификаторов, чтобы выбрать обратно на сервер, это может занять некоторое время. Я не уверен, что есть хороший способ сделать это в транзакции, но я понимаю, что Django всегда просто отправляет список и говорит ВЫБИРАТЬ... Где pk в (...,...,...) в основном. В этом случае, если предварительно выбранные данные разрежены (скажем, объекты штата США, связанные с адресами людей), это может быть очень хорошо, однако если он ближе к одному к одному, это может привести к потере большого количества коммуникаций. Если вы сомневаетесь, попробуйте оба и посмотрите, что работает лучше.

все, что обсуждалось выше, в основном касается связи с базой данных. На стороне питона, однако prefetch_related имеет дополнительное преимущество, что используется один и тот же объект для представления каждого объекта в базе данных. С select_related дубликаты объектов будут созданы в Python для каждого "родительского" объекта. Поскольку объекты в Python имеют приличный бит памяти, это также может быть рассмотрено.

оба метода достигают одной и той же цели, чтобы отказаться от ненужных запросов к БД. Но они используют разные подходы для повышения эффективности.

единственная причина использовать любой из этих методов - это когда один большой запрос предпочтительнее многих маленьких запросов. Django использует большой запрос для упреждающего создания моделей в памяти, а не для выполнения запросов по требованию к базе данных.

select_related выполняет соединение с каждым поиском, но расширяет выбор, чтобы включить столбцы всех Соединенных таблиц. Однако этот подход имеет один нюанс.

соединения могут умножать количество строк в запросе. При выполнении соединения по внешнему ключу или по полю один к одному количество строк не увеличивается. Однако многие из многих соединений не имеют этой гарантии. Итак, Джанго ограничивает select_related к отношениям, которые не будут неожиданно приводить к массовому соединению.

The "присоединиться к python" на 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);

вместо выполнения одного соединения с потенциально слишком большим количеством строк, каждая таблица разбивается на отдельный запрос.

Comments

    Ничего не найдено.