В чем разница между select related и prefetch related в Django ORM?
в Django doc,
select_related()"следует" за отношениями внешнего ключа, выбирая дополнительные данные связанных объектов при выполнении запроса.
prefetch_related()выполняет отдельный поиск для каждого отношения и выполняет" присоединение " в Python.
что значит "делать присоединение в python"? Может кто-нибудь проиллюстрировать на примере?
Я понимаю, что для внешнего ключа отношения, используйте select_related; и для отношения М2М, используйте prefetch_related. Это правильно?
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_relatedfor.компромиссы заключаются в том, что
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