我有创建(或接收)交易的用户。我拥有的交易层次结构是一个多表继承,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
's wonderful IneritanceManager
,效果很好。除了当我在传输子模型的接收者 FK 字段上包含过滤时,数据库查询增加了一个数量级。
如上所示,我在 Transactionuser
列和 Transferrecipient
列上放置了索引。但在我看来,如果可能的话,我可能需要一个关于 Transaction 子类型的索引。我试图通过在 Transactiontype
字段上放置索引并将其包含在查询中来实现此效果,如下所示,但这似乎没有效果。此外,我使用.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
?我错过了什么吗?我在做傻事吗?或者有没有办法可以进一步优化?