【发布时间】:2020-11-27 08:19:50
【问题描述】:
我正在尝试优化我在预取中使用的 Django(版本 1.11)中的查询。所以我有一个与工资相关的 StaffProfile 模型,如下所示:
class Wages(Model):
# ...
staff = models.ForeignKey('StaffProfile', on_delete=models.CASCADE, null=True)
title = models.CharField(_('Title'), max_length=50)
class StaffProfile(Model):
# ...
objects = StaffProfileManager.from_queryset(StaffQuerySet)()
StaffQuerySet 有一个专门的方法:
class StaffQuerySet(QuerySet):
def my_prefetch(
) -> QuerySet:
return self.prefetch_related(
Prefetch(
'wages_set',
queryset=Wages.objects.filter(
# ...
).order_by(
Upper('title')
),
to_attr='prefetched_wages'
),
)
我注意到当我运行这个查询时:Wages.objects.all().order_by(Upper('title')) 我的数据库(PostgreSQL)显然对结果进行了排序(下面是 EXPLAIN 在生成的 SQL 上运行的输出):
Sort (cost=21.31..21.86 rows=220 width=166)
Sort Key: (upper((title)::text))
-> Seq Scan on staff_wages (cost=0.00..12.75 rows=220 width=166)
生成的查询是:
In [25]: str(Wages.objects.all().order_by(Upper('title')).only('title').query)
Out[25]: 'SELECT "staff_wages"."uuid", "staff_wages"."title" FROM "staff_wages" ORDER BY UPPER("staff_wages"."title") ASC'
所以我尝试在title 字段上设置索引。为了实现这一点,我创建了一个迁移:
class Migration(migrations.Migration):
dependencies = [
('staff', '0020_merge_20201116_0929'),
]
operations = [
migrations.RunSQL(
sql='CREATE INDEX "staff_wages_title_upper_idx" ON "staff_wages" (UPPER("title"));',
reverse_sql='DROP INDEX "staff_wages_title_upper_idx";'
)
]
我已经运行它,我看到它是在数据库中创建的。但是,当我现在运行查询时,EXPLAIN 给出完全相同的输出,而我希望它使用我的索引。我究竟做错了什么?我应该使用与 b-tree 不同的索引吗?还是无法实现我想要的?
【问题讨论】:
-
WHERE生成的子句.filter(...)也需要考虑。 -
生成的SQL语句到底是什么,表是如何定义的。
-
@LaurenzAlbe 我已经用生成的查询更新了我的问题。
标签: django postgresql indexing django-orm