Как оптимизировать вложенные внешние ключи в наборе запросов Django - PullRequest
0 голосов
/ 26 февраля 2020

TLDR;

Есть ли лучший способ обработки глубоких вложений в этом Django запросе?

File.objects.filter(folder__project__workspace__organization__in=user.organizations.all())

Подробный вопрос :

Вот пример сценария:

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

class User(models.Model):
    pass


class Organization(models.Model):
    members = models.ManyToManyField(
        User, through='OrganizationMembership', related_name='organizations'
    )

class OrganizationMembership(models.Model):
    member = models.ForeignKey(User)
    organization = models.ForeignKey(Organization)

Вложенные отношения Среди моделей определены следующие:

class Workspace(models.Model):
    organization = models.ForeignKey(Organization, related_name='workspaces')


class Project(models.Model):
    workspace = models.ForeignKey(Workspace, related_name='projects')


class Folder(models.Model):
    project = models.ForeignKey(Project, related_name='folders')


class File(models.Model):
    folder = models.ForeignKey(Folder, related_name='files')

Я хотел отфильтровать все файлы, к которым запрашивающий пользователь имеет доступ в разных организациях. Вот мой набор запросов, есть ли способ оптимизировать этот набор запросов?

user = self.request.user
organizations = user.organizations.all()

File.objects.filter(folder__project__workspace__organization__in=organizations)

Ответы [ 2 ]

1 голос
/ 26 февраля 2020

Используйте «запрос», чтобы получить сгенерированный SQL:

MyModel.objects.filter(name="my name").query

Я думаю, что нет лучшего способа, чем ваш текущий метод.

0 голосов
/ 26 февраля 2020

Подход: rather than running one complex and large query(having multiple joins), run small simple queries on DB

Данное решение может быть более оптимальным, чем решение, полученное путем объединения нескольких таблиц, что в приведенном выше коде выше.

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

user = self.request.user
organizations = user.organizations.all()
organizations_ids = organizations.values_list('id', flat=True)
reduced_organization_qs = Organization.objects.filter(ids__in=organizations_ids)
reduced_organization_ids = reduced_organization_qs.values_list('id', flat=True)

reduced_workspace_qs = Workspace.objects.filter(organizations_ids=reduced_organization_ids)
reduced_workspace_ids = reduced_workspace_qs.values_list('id', flat=True)


reduced_project_qs = Project.objects.filter(workspace_id__in=reduced_workspace_ids)
reduced_project_ids = reduced_project_qs.values_list('id', flat=True)

reduced_folder_qs = Folder.objects.filter(project_id__in=reduced_project_ids)
reduced_folder_ids = reduced_folder_qs.values_list('id', flat=True)

reduced_file_qs = File.objects.filter(folder_id__in=reduced_folder_ids)

Что я делаю, я пропускаю объединение таблиц и только потому, что индекс id , восстановление идентификаторов будет очень быстрым.

...