python - Django 聚合需要很多时间
问题描述
我有一个定义如下的模型
class Image(model.Models):
# Stages
STAGE_TRAIN = 'train'
STAGE_VAL = 'val'
STAGE_TEST = 'test'
STAGE_TRASH = 'trash'
STAGE_CHOICES = (
(STAGE_TRAIN, 'Train'),
(STAGE_VAL, 'Validation'),
(STAGE_TEST, 'Test'),
(STAGE_TRASH, 'Trash'),
)
stage = models.CharField(max_length=5, choices=STAGE_CHOICES, default=STAGE_TRAIN)
commit = models.ForeignKey(Commit, on_delete=models.CASCADE, related_name="images", related_query_name="image")
在我的数据库中,我有 170k 图像,我尝试使用一个端点来按阶段计算所有图像
目前我有类似的东西
base_query = Image.objects.filter(commit=commit_uuid).only('id', 'stage')
count_query = base_query.aggregate(count_train=Count('id', filter=Q(stage='train')),
count_val=Count('id', filter=Q(stage='val')),
count_trash=Count('id', filter=Q(stage='trash')))
但这大约需要 40 秒,当我尝试在我的 shell 中查看 SQL 请求时,我有一些看起来不错的东西
{'sql': 'SELECT COUNT("image"."id") FILTER (WHERE "image"."stage" = \'train\') AS "count_train", COUNT("image"."id") FILTER (WHERE "image"."stage" = \'val\') AS "count_val", COUNT("image"."id") FILTER (WHERE "image"."stage" = \'trash\') AS "count_trash" FROM "image" WHERE "image"."commit_id" = \'333681ff-886a-42d0-b88a-5d38f1e9fe94\'::uuid', 'time': '42.140'}
另一个奇怪的事情是,如果我改变我的聚合函数
count_query = base_query.aggregate(count_train=Count('id', filter=Q(stage='train')&Q(commit=commit_uuid)),
count_val=Count('id', filter=Q(stage='val')&Q(commit=commit_uuid)),
count_trash=Count('id', filter=Q(stage='trash')&Q(commit=commit_uuid)))
当我这样做时,查询的速度是原来的两倍(仍然是 20 秒),当我显示 SQL 时,我看到提交的过滤器是在FILTER
所以我有两个问题:
我可以做一些不同的事情来提高查询速度,还是应该将计数存储在某处并在每次更改图像时更改值?
我期待查询首先在提交 id 上进行过滤,然后
stage
在
解决方案
1)您可以使用index_together
选项添加字段索引
class Image(model.Models):
class Meta:
index_together = [['stage'], ['stage', 'commit']]
或indexes
选项(参见https://docs.djangoproject.com/en/2.0/ref/models/options/#django.db.models.Options.indexes)
class Image(model.Models):
class Meta:
indexes = [models.Index(fields=['stage', 'commit'])]
2)您不需要查找id
:
base_query = Image.objects.filter(commit=commit_uuid).only('stage')
# count images in stages
count = base_query.aggregate(train=Count(1, filter=Q(commit=commit_uuid) & Q(stage='train')),
val=Count(1, filter=Q(commit=commit_uuid) & Q(stage='val')),
trash=Count(1, filter=Q(commit=commit_uuid) & Q(stage='trash')))
推荐阅读
- r - spark_read_parquet 中的 columns 选项
- javascript - 网址生成器功能
- go - 调试时如何在 Visual Studio Code 中查看全局变量?
- python - 无法模拟从另一个类继承的类(创建/使用单例对象)
- sql - 编写 SQL INSERT 从两个独立的相关行中检索其数据
- popup - tvOS 上的 Toast/弹出窗口
- cordova - Meteor/Cordova:帐户密码在登录/注册时破坏应用程序
- java - 如何修复“App Engine SDK 已过期”?
- javascript - 如何使用 javascript 或 jquery 在程序上调整具有像素精度的媒体查询?
- angular - 升级到最新版本后,ng-select 下拉菜单在 UI 上中断 - Angular 6