django - 使用 Prefetch 提高具有数百万行的子查询中的计数性能
问题描述
我有一个监控来自网站的事件的应用程序,部分用户界面显示给定时间段内每个网站的事件计数。以下是模型的外观:
class Website(models.Model):
name = models.CharField(max_length=64)
url = models.TextField()
class Event(models.Model):
website = models.ForeignKey(Website, related_name="events")
created_at = models.DateTimeField(default=timezone.now)
ip_address = models.CharField(max_length=64)
status = models.CharField(max_length=16)
message = models.CharField(max_length=128)
这些网站每天产生数千个事件,因此Event
与其他表相比,该表相当大。这是我试图生成的查询的样子:
eargs = {
"website": OuterRef("pk"),
"created_at__gte": some_start_time,
"created_at__lt": some_end_time
}
events = Event.objects.filter(**eargs).values("website")
events_count = events.annotate(c=Count("*").values("c")[:1]
websites = Website.objects.annotate(events=Coalesce(Subquery(events_count,
output_field=IntegerField()), 0)
就像我之前提到的,该Events
表中有数百万行。对于少数网站,此查询不会花费太长时间。但是当有100个或更多的网站时,需要相当长的时间。我做了一些分析,数据库(内部)正在查询每个网站的计数。因此,如果我有 100 个网站,数据库将进行 100 个查询来生成计数(仍然有一个查询来自 Django,但 Postgres 在内部进行了这 100 个子查询)。
我想做的是预取这些计数,因为当我运行以下原始 SQL 时,它实际上非常快:
SELECT
website_id,
COUNT(*)
FROM
myapp_events
WHERE
created_at >= some_start_time AND created_at < some_end_time
GROUP BY
website_id;
是否有任何可能的方法来预取该查询并仍然使用我的 QuerySet 中的结果?还是我把这一切都搞错了?这似乎是一件很常见的事情,我很难思考如何加快速度。
解决方案
推荐阅读
- python - 通过python从某些网站获取数据
- vue.js - 部署到 vercel 的 Vue 应用程序不呈现
- javascript - 使javascript迭代类似于python
- java - Java 可以更快地完成这个 BitSet.or 比较吗?
- android - 如何设置 MaterialButton 图标大小以适应约束?
- mysql - 从MySQL读取数据时,Xamarin表单无法仅在UWP中读取结果集
- c# - 当窗口构造函数将字符串作为参数时数据绑定失败(OxyPlot,WPF)
- angular - Plesk 上的 Angular Universal Build - 查看页面源不呈现
- r - 如何将数据集的列乘以常数?
- windows - 为什么“which -a”在 Git Bash for Windows 中显示多个(相同)条目?