Как правильно определить индекс для эффективного запроса обратного отношения для полей ForeignKey? (Django)
Так что я провел несколько дней в поисках ответа на этот вопрос, и, к моему удивлению, я не могу найти никого, кто задавал бы этот конкретный вопрос, а также упоминаний о том, что я запутался в этом вопросе. Мое замешательство заключается, я полагаю, в том, что я не уверен, как именно Django строит запросы под капотом, вокруг запроса обратного отношения model_set, или его related_name указано как.
Идеально было бы, если бы начало ORM-запроса с parent_instance.related_name
работало точно так же, как и RelatedModel.objects
, чтобы, например, запрос parent_instance.related_name.filter(token__in=somelist)
мог использовать простой индекс поля «token», созданный с db_index=True, точно так же, как такой индекс можно было бы использовать с помощью RelatedModel.objects.filter(token__in=somelist)
. Однако эти два запроса не эквивалентны; чтобы быть эквивалентными, второй запрос должен быть изменен на RelatedModel.objects.filter(parent=parent_instance, token__in=somelist)
(или в обратном порядке, RelatedModel.objects.filter(token__in=somelist, parent=parent_instance)
).
Это наводит меня на мысль, что для использования преимуществ индексирования при запросах к обратным отношениям foreignKey родительская модель, скорее всего, должна быть частью всех индексов, которые вы планируете использовать. Если человек разбирается в базах данных (а я в какой-то степени разбираюсь, хотя это далеко не моя сильная сторона), это может быть очевидно, но многие программисты в наше время не разбираются, и мне трудно поверить, что люди просто осознают, что родительская модель должна быть включена в индексы для запросов related_set, учитывая, что при запросе с использованием формы instance.related_set(...)
.
Вот почему я немного шокирован тем, что мне так трудно найти ответ на этот вопрос... и не только этим, но и тем, что я не могу найти даже обсуждения на эту тему или просто заданный вопрос. Я бы и сам еще долго пытался найти ответ, но моя компания настаивает на том, чтобы я был в команде разработчиков всего один, и они дышат мне в затылок, чтобы я обновил эту штуку, повысив эффективность. И кстати, пока никто не ругает меня, я недавно установил панель отладки django, но я сделал довольно масштабные изменения и пытаюсь довести их до того уровня, когда я смогу запустить эту штуку снова локально (извлек ли я уроки о том, как структурировать оптимизационные изменения в маленькие, дискретные ветки и коммиты? Да, конечно! Боль - очень эффективный учитель).
В любом случае, мне кажется, что Djago, возможно, нашел способ обработать это под капотом, чтобы запрос обратного отношения related_set позволял использовать индекс так же, как он может быть использован при запросе из RelatedModel.objects
, просто потому, что, ну, действительно ли людям нужно добавлять дополнительные составные индексы для каждого поля, которое они планируют запрашивать через обратное отношение, когда их приложение содержит запрос как в целом, так и через обратное отношение? Например, если вам нужно запросить диапазон и/или список значений по первичному ключу, и вам нужно запросить поле «токен», и вам иногда нужно сделать это, не ограничивая запрос конкретным «родительским» экземпляром модели, а иногда только для конкретного родительского экземпляра, то вот как вы бы выполнили определение эффективных индексов:
class ParentModel(models.Model):
...
class Meta:
indexes = [
models.Index(fields=['related_set', 'id']),
models.Index(fields=['related_set', 'token']),
]
class RelatedModel(models.Model):
... (allowing primary key to default to id, which is automatically indexed)
token = models.CharField(..., db_index=True)
parent = models.ForeignKey(ParentModel, related_name='related_set') # Using 'related_set' here for clarity of the example, I know it's redundant
class Meta:
indexes = [
# Clearly these compound indexes would be needed for querying RelatedModel.objects,
# when it is required to narrow the search to one or more parent instances, so no confusion here
models.Index(fields=['parent', 'token']),
models.Index(fields=['parent', 'id']),
]
Мой вопрос связан с индексами, предложенными выше для ParentModel. Будут ли они необязательны для запроса в форме parent_instance.related_set.filter(...)
? Или составные индексы, определенные в RelatedModel, будут работать как для этой формы, так и для формы RelatedModel.objects.filter(parent=parent_instance, id=xxx/token=xxx)
?
Или я страдаю от недосыпания и переутомления в сочетании с ношением неподобающего количества шляп, и я не могу думать об этом правильно и упускаю что-то очевидное? Не может же быть, чтобы простое значение db_index=True для поля 'token', и ничего больше, позволило бы parent_instance.related_set.filter(token=value)
использовать индекс, не так ли?
EDIT: Как я думаю об этом, кажется, что индексы должны быть созданы в определении модельного класса RelatedModel, поскольку, в конце концов, это те экземпляры, которые запрашиваются/извлекаются. Но при использовании related_set вы отталкиваетесь от родительского экземпляра модели, так что, возможно, это не так. Если действительно будут использоваться индексы, определенные в ParentModel, то очевидно, что крайнее левое поле должно быть 'related_set'.
НО, если индексы должны быть определены в RelatedModel, то мне кажется, что вам нужно создать составные индексы для ['parent', 'field'], с parent в качестве самого левого поля. Но что тогда, если вы запросили ParentModel, чтобы найти экземпляр для запроса? Например, если у меня есть запрос ParentModel.filter(somefield__startswith='node_')
, и я хочу найти все экземпляры RelatedModel, связанные с этим экземпляром (экземплярами) через обратное отношение related_set, которые имеют token=somevalue, как мне построить этот индекс и где?
Спасибо за любое понимание!