我有一些表在两个单独的Django模型中没有通过FK关系连接,我正在尝试SubQuery
。数据如下所示:
# "master" data table - reflects real property ownership by humans
# there are often changes to property ownership
class OwnershipRecord(Model):
parcel = CharField(max_length=10, unique=True)
owner_name = ...
other data fields ...
# Poor man's 'elastic search' or an index of sorts for OwnershipRecord
class Lead(Model):
ownership_record = OneToOneField(OwnershipRecord)
preforeclosure = BooleanField(default=False)
aggregated data/booleans/etc...
# "descriptor" table for a property
# there are not often changes to a property's physical traits
ResidentialMasterRecord(Model):
parcel = CharField(max_length=10, unique=True) # These are the SAME as OwnershipRecord
livablesqft = ...
lotsqft = ...
所以我正在开发一个可以按平方英尺过滤Lead
个对象的查询。 Lead
与OwnershipRecord
相关,但与ResidentialMasterRecord
没有任何关系 - 它作为“事实表”存在,类似于特定地址的一组坐标。< / p>
我认为SubQuery
适用于这种情况,我可以引用parcel
和OwnershipRecord
中的ResidentialMasterRecord
来链接两个实时。
非常慢。这是我正在尝试的查询:
from django.db.models import OuterRef, SubQuery
from myapp.models import OwnershipRecord, Lead, ResidentialMasterRecord
RMR_SQ = ResidentialMasterRecord.objects \
.filter(parcel=OuterRef("ownership_record__parcel"))
qs = Lead.objects.select_related('ownership_record') \
.annotate(sqft=SubQuery(RMR_SQ.values("livablesqft")[:1])) \
.filter(sqft__gte=1500)
我正在查看15-45分钟范围内的查询时间 - 但我最终会得到结果...... 有关如何在保持非外键密钥结构的同时加速这一事情的任何想法?
Django 1.11.8 PostgreSQL 9.5 Droplet w / 8GB RAM,4核
答案 0 :(得分:1)
(1)即使底层数据库没有fkey关系,也可以在ORM中指定两个表相关。
(2)像@bma提到的那样,索引会对性能产生很大的影响。
但是,在这里,通常是我的策略 - 将子查询分解为两个单独的查询并将一些数据保存在内存中。
如,
def chunkify(rg, chunk_size=1000):
while rg:
yield rg[:chunk_size]
rg = rg[chunk_size:]
min_sq_footage = 1500
master_records = ResidentialMasterRecords.objects.filter(sqft__gte=min_sq_footage)
parcels = list(master_records.values_list('parcel', flat=True))
for parcel_chunk in chunkify(parcels):
qs = Lead.objects.select_related('ownership_record').filter(ownership_record__parcel__in=parcel_chunk)
# do some work
答案 1 :(得分:1)
这个答案是@bma和@wholevinski的评论灵感的结果。
如Django docs中所述,
在ForeignKey上自动创建数据库索引。
此子查询问题的关键是在JOIN
字段上建立索引(就我的问题而言,又名:parcel
)。这很简单,看起来像这样:
class OwnershipRecord(Model):
parcel = CharField(max_length=10, unique=True,
db_index=True)
owner_name = ...
other data fields ...
ResidentialMasterRecord(Model):
parcel = CharField(max_length=10, unique=True,
db_index=True)
livablesqft = ...
lotsqft = ...
这个docs很稀疏,但很容易实现。
<强> db_index 强>
Field.db_index
如果 True ,将为此字段创建数据库索引。
结果:我的查询时间从约30分钟变为1.55秒。
>>> import timeit
>>> from django.db.models import OuterRef, Subquery
>>> from leads.models import Lead
>>> from ownership.models import OwnershipRecord
>>> from mcassessor.models import ResidentialMasterRecord
>>> rmr_sq = ResidentialMasterRecord.objects.filter(parcelid=OuterRef('ownership_record__parcel'))
>>> qs = Lead.objects.select_related('ownership_record').annotate(sqft=Subquery(rmr_sq.values("livablesqft")[:1])).filter(sqft__gte=1700)
>>> toc = timeit.default_timer()
... qs_list = list(qs)
... print(timeit.default_timer() - toc)
[Out] 1.55457401276
>>> len(qs_list)
[Out] 823