Как правильно определить индекс для эффективного запроса обратного отношения для полей 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, как мне построить этот индекс и где?

Спасибо за любое понимание!

Вернуться на верх