我有创建(或接收)交易的用户。我拥有的事务层次结构是多表继承,以Transaction
为基础模型,其中包含所有事务类型(例如,用户(FK),金额等)之间的公共字段。我有几种事务类型,它们进行了扩展具有特定类型数据的Transaction
模型。
为了这个示例,可以在下面找到说明我的问题的简化结构。
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
出色的IneritanceManager
,效果很好。除了在转移子模型的收件人FK字段上包括过滤功能之外,数据库查询会增加一个数量级。
如上所述,我已将索引放在“事务user
”列和“转移recipient
”列上。但是在我看来,如果可能的话,我可能需要的是Transaction子类型的索引。我试图通过在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
时,为什么数据库查询会有一个数量级的差异?我错过了什么吗?我在做傻事吗?还是有办法进一步优化?