postgresql Django ORM:在注解子查询后移动过滤器

hgqdbh6s  于 2023-04-29  发布在  PostgreSQL
关注(0)|答案(2)|浏览(124)

Django ORM声明:

Model.objects.all() \
    .annotate(
        ord=Window(
            expression=RowNumber(),
            partition_by=F('related_id'),
            order_by=[F("date_created").desc()]
        )
    ) \
    .filter(ord=1) \
    .filter(date_created__lte=some_datetime)

导致以下SQL查询:

SELECT * 
FROM (
    SELECT 
      id, related_id, values, date_created
      ROW_NUMBER() OVER (
        PARTITION BY related_id
        ORDER BY date_created DESC
      ) AS ord
    FROM model_table
    WHERE date_created <= 2022-02-24 00:00:00+00:00
)
WHERE ord = 1

可以看到,date_created__lte过滤器应用于内部查询。是否可以控制语句位置精确器并将过滤器移到外部,如ord

j5fpnvbx

j5fpnvbx1#

在您的例子中,您可以将date_created__lte过滤器移动到annotate方法之前,以确保它应用于基本查询。这也将提高查询性能,因为annotate方法适用于较小的过滤数据集。

Model.objects.filter(date_created__lte=some_datetime) \
    .annotate(
        ord=Window(
            expression=RowNumber(),
            partition_by=F('related_id'),
            order_by=[F("date_created").desc()]
        )
    ) \
    .filter(ord=1)
xdyibdwo

xdyibdwo2#

我找到了一种方法来实现我想要的结果:在注解查询之外应用过滤器,在本例中为date_created__lte

sub = Model.objects.all() \
    .annotate(
        ord=Window(
            expression=RowNumber(),
            partition_by=F('related_id'),
            order_by=[F('date_created').desc()]
        )
    ) \
    .filter(ord=1)

Model.objects.all() \
    .filter(id__in=sub.values_list('id')) \
    .filter(date_created__lte=some_datetime)

然而,这不是我想要的代码,从性能的Angular 来看,由于HASH JOIN,它很糟糕。当然,我可以编写一个原始的SQL查询,通过Django ORM解析值,但是对于一个简单的嵌套子查询来说,这看起来太重了。所以,一个更好的答案是赞赏🙏

相关问题