我们在项目中使用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 查询
中的参数答案 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
,但LIMIT
和OFFSET
,这很奇怪。这没有多大意义。