Оптимизация запросов для ассоциации FK на унаследованной модели из базовой модели - PullRequest
0 голосов
/ 13 марта 2020

У меня есть пользователи, которые создают (или получают) транзакции. У меня есть иерархия транзакций, состоящая из нескольких таблиц, с Transaction в качестве базовой модели, содержащей общие поля для всех типов транзакций, таких как Пользователь (FK), сумма и т. Д. c. У меня есть несколько типов транзакций, которые расширяют модель Transaction с указанием типа c data.

Ради этого примера ниже приведена упрощенная структура, иллюстрирующая мою проблему.

from model_utils.managers import InheritanceManager

class User(models.Model):
    pass

class Transaction(models.Model):
    DEPOSIT = 'deposit'
    WITHDRAWAL = 'withdrawal'
    TRANSFER = 'transfer'

    TYPES = (
        (DEPOSIT, DEPOSIT),
        (WITHDRAWAL, WITHDRAWAL),
        (TRANSFER, TRANSFER),
    )

    type = models.CharField(max_length=24, choices=TYPES)
    user = models.ForeignKey(User)
    amount = models.PositiveIntegerField()

    objects = InheritanceManager()

    class Meta:
        indexes = [
            models.Index(fields=['user']),
            models.Index(fields=['type'])
        ]

class Withdrawal(Transaction):
    TYPE = Transaction.WITHDRAWAL
    bank_account = models.ForeignKey(BankAccount)

class Deposit(Transaction):
    TYPE = Transaction.DEPOSIT
    card = models.ForeignKey(Card)

class Transfer(Transaction):
    TYPE = Transaction.Transfer
    recipient = models.ForeignKey(User)

    class Meta:
        indexes = [
            models.Index(fields=['recipient'])
        ]

Затем я устанавливаю тип каждой транзакции в методе .save() унаследованной модели. Это все хорошо и хорошо.

Проблема возникает, когда я хочу получить транзакции пользователя. В частности, мне требуются экземпляры подмодели (депозиты, переводы и снятие средств), а не базовая модель (транзакции). Мне также требуются транзакции, которые пользователь создал сам, и переводы, которые он получил. Для первого я использую django-model-utils's fantasti c IneritanceManager, который прекрасно работает. За исключением того, что когда я включаю фильтрацию в поле FK получателя подмодели переноса, запрос БД увеличивается на порядок.

Как показано выше, я поместил индексы в столбец Транзакция user и Перевод recipient колонка. Но мне показалось, что мне может понадобиться индекс подтипа Transaction, если это вообще возможно. Я попытался добиться этого эффекта, поместив индекс в поле «Транзакция type» и включив его в запрос, как вы увидите ниже, но, похоже, это не имеет никакого эффекта. Кроме того, я использую .select_related() для пользовательских объектов, поскольку они требуются для сериализации.

Запрос структурирован следующим образом:

from django.db.models import Q

    queryset = Transaction.objects.select_related(
         'user',
         'transfer__recipient'
    ).select_subclasses().filter(
         Q(user=request.user) |
         Q(type=Transaction.TRANSFER, transfer__recipient=request.user)
    ).order_by('-id')

Так что мой вопрос: почему существует разница в величине в запросе БД при включении Transfer.recipient в запрос? Я что-то пропустил? Я делаю что-то глупое? Или есть способ, которым я могу оптимизировать это дальше?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...