从分组列中重复采样的最佳性能

时间:2016-03-21 15:06:17

标签: sql postgresql aggregate-functions postgresql-performance

此问题与first_value()的功能有关,使用其他功能或解决方法。

这也是关于大表中“性能上的微不足道”。使用例如。在下面解释的上下文中,max()要求虚假比较。即使速度很快,也会产生一些额外的成本。

这个典型的查询

SELECT x, y, count(*) as n 
FROM t 
GROUP BY x, y;

需要重复GROUP BY中的所有列才能返回多个列。执行此操作的语法糖是使用位置引用:

SELECT x, y, count(*) as n 
FROM t 
GROUP BY x, 2  -- imagine that 2, 3, etc. are repeated with x

有时候不仅需要糖,还需要一些语义来理解复杂的背景:

SELECT x, COALESCE(y,z), count(*) as n 
FROM t 
GROUP BY x, y, z  -- y and z are not "real need" grouping clauses?

我可以想象许多其他复杂的背景。让我们看看通常的解决方案:

SELECT x, max(y) as y, count(*) as n 
FROM t 
GROUP BY x  -- best semantic! no need for other columns here

其中max()函数可以是任何“sample()”(例如,第一个或最后一个值)。无效的东西的表现优于max(),例如聚合函数first_value(),但需要WINDOW,因此性能下降。有一些旧的建议to implement first/last agg functions in C

是否有一些“快速获取任何一个值”的聚合函数,其性能优于max()GROUP BY X,2,...
也许是最近发布的一些新功能?

2 个答案:

答案 0 :(得分:8)

如果您真的不关心选择该集合中的哪个成员,并且您不需要计算其他聚合(例如计数),则可以使用DISTINCT ON (x) 进行快速而简单的替换没有 ORDER BY

SELECT DISTINCT ON (x) x, y, z FROM t;

xyz来自同一行,但该行是来自具有相同x的每组行的任意选择。

如果您还需要 count ,那么您在性能方面的选项是有限的,因为在任何一种情况下都必须读取整个表格。不过,您可以将它与窗口函数组合在同一SELECT

SELECT DISTINCT ON (x) x, y, z, count(*) OVER (PARTITION BY x) AS x_count FROM t;

考虑SELECT查询中的事件序列:

根据要求,可能可以更快地获取计数:

结合GROUP BY我认为获得一些表现的唯一现实选择是first_last_agg extension。但是不要期待太多。

对于没有计数的其他用例(包括顶部的简单案例),有更快的解决方案,具体取决于您的确切用例。特别是获得每组的“第一”或“最后”值。模拟松散的索引扫描。 (如@Mihai commented):

答案 1 :(得分:5)

不是一个官方来源,但有些想法被认为是一个相当普遍的问题:

通常聚合器需要处理所有匹配的行。从您的问题文本中,您可以定位尝试识别特定值(最大值,最小值,第一个,最后一个,第n个等)的聚合器。这些可以从维护特定此类聚合器的适当值的数据结构中受益。然后“选择”该值可以大大加快 例如。一些数据库跟踪列的最大值和最小值 您可以将此支持视为高度专业化的内部索引,由系统本身维护而不是(直接)控制用户。

现在,postgresql更多地关注有助于改善查询的支持,而不仅仅是特殊情况。因此,他们避免加大力度来加速明显不利于广泛用例的特殊情况。

回到加速样本值聚合器。

聚合器必须在一般情况下处理所有行,而不是一般策略允许短路对尝试识别特定值的聚合器的需求(现在的样本类聚合器),显然任何重构的查询都是不会导致需要处理的行集减少,需要相似的时间才能完成。

为了加速处理所有行之外的此类查询,您将需要一个支持数据结构。对于数据库,这通常以索引的形式提供。

您还可以从允许减少要读取的行数的特殊执行操作中受益。

使用pg,您可以提供自己的索引实现。因此,您可以添加一个最能支持您感兴趣的特殊聚合器的实现。(至少在您需要经常运行此类查询的情况下。)

此外,执行操作如 index仅扫描使用递归查询进行延迟评估可能允许以比“直接”编码更快的速度编写特定查询。 / p>

如果您的问题更多地针对一般方法,您可以更好地向研究人员咨询有关此类主题的信息,这超出了SO旨在提供的任何内容。

如果您有特定的(一组)查询需要改进,那么提供明确的问题可能会让社区帮助识别潜在的优化。试图在没有良好测量基础的情况下进行优化是无处可去的,因为在一种情况下产生完美结果可能会在另一种情况下导致性能下降。