使用Prefetch提高具有数百万行的子查询中计数的性能

时间:2019-06-06 21:46:01

标签: django postgresql

我有一个监视网站事件的应用程序,部分用户界面显示给定时间段内每个网站的事件计数。这些模型如下所示:

[ 
  {
    "name" : "test1",
    "city" : "London",
    "applications" : [
        {
            "app" : "stackoverflow",
            "app_city" : "New York",
             "app_hobies" : [ {
                 "hobby" : "football",
                 "hobby_time" : "daily"}
             }]
      }]

这些网站每天产生数千个事件,因此[ { "_id" : ObjectId("12121"), "name" : "test1", "city" : "London", "applications" : [ { "_id" : ObjectId("4343"), "app" : "stackoverflow", "app_city" : "New York", "app_hobies" : [ { "_id" : ObjectId("21322"), "hobby" : "football", "hobby_time" : "daily"} }] }] 表与其他表相比非常大。这是我要生成的查询的样子:

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表中包含数百万行。对于少数网站,此查询不会花费太长时间。但是,当有100个或更多的网站时,它会花费相当长的时间。我已经进行了一些分析,数据库(内部)正在查询每个网站的计数。因此,如果我有100个网站,则数据库将进行100个查询以生成计数(仍然有一个查询来自Django,但Postgres内部正在进行这100个子查询)。

我想做的是预取这些计数,因为当我运行以下原始SQL时,它实际上非常快:

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)

有没有可能预取该查询并仍在QuerySet中使用结果的方法?还是我把这一切弄错了?似乎这是很平常的事,我很难把头放在如何加快速度上。

0 个答案:

没有答案