PostgREST使用子查询或CTE中的限制和偏移量

时间:2018-05-29 21:35:48

标签: postgresql postgrest

我们在项目中使用PostgREST来处理一些相当复杂的数据库视图。

从某些角度来看,当我们使用限制和偏移(x范围标题或查询参数)和子选择时,我们会得到非常高的响应时间。

从我们读过的内容来看,这似乎是一个已知的问题,即postgresql执行子选择,即使对于未请求的记录也是如此。解决方案是使用偏移和限制稍微摇晃,将其放在子选择或CTE表中。

是否存在我们可以在数据库视图中使用的内部GUC值或类似值以优化响应时间?有人提示如何实现这个目标吗?

编辑:这里建议的是更多细节。我们假设产品和零件之间存在关系。我想知道每个产品的部件数量(这是我们公开的数据库视图的简化版本)。

有两种方法可以做到这一点

:一种。子选择:

    SELECT products.id
            ,(
                    SELECT count(part_id) AS total
                    FROM parts
                    WHERE product_id = products.id
                    )
    FROM products limit 1000 OFFSET 99000

B中。 CTE:

    WITH parts_count
    AS (
            SELECT product_id
                    ,count(part_id) AS total
            FROM parts
            GROUP BY product_id
            ORDER BY product_id
            )
    SELECT products.id
            ,parts_count.total
    FROM products
    LEFT JOIN parts_count ON parts_count.product_id = product.id 
    LIMIT 1000     
    OFFSET 99000

A 的问题是对每一行执行子选择,所以即使我只读了1000条记录,也有10万个子选择。

B 的问题是,与parts_count表的连接需要很长时间,因为那里有100个0000记录(尽管带有查询的2000个记录只有200毫秒!)。理想情况下,我想限制parts_count表与主查询具有相同的限制和偏移但我不能在PostgREST中执行此操作,因为它只是在最后添加限制和偏移,我无法访问到 WITH 查询

中的参数

1 个答案:

答案 0 :(得分:1)

OFFSET导致表现不佳是不可避免的。

没有其他方法可以计算OFFSET,但要扫描并丢弃所有行,直到达到偏移量为止,如果OFFSET为高,则世界上没有数据库会很快。

这是一个概念性问题,避免它的唯一方法是避免OFFSET

如果您的目标是分页,那么通常keyset pagination是更好的解决方案:

添加符合要求的ORDER BY子句,确保ORDER BY子句中有唯一键,并记住找到的最后一个值。要获取下一页,请添加包含该值的WHERE条件。有了适当的索引支持,这可以非常快。

对于您的查询,可能是更高效的版本:

SELECT p.id
       count(parts.part_id) AS total
FROM (SELECT id FROM products
      LIMIT 1000 OFFSET 99000) p
   LEFT JOIN parts ON parts.product_id = p.id
GROUP BY p.id;

您没有ORDER BY,但LIMITOFFSET,这很奇怪。这没有多大意义。