如何在Postgres中加速min / max聚合而不使用其他不必要的索引

时间:2013-07-24 17:41:34

标签: sql performance postgresql

假设我有一个带有int列的表,我将要读取的是MAX()int值。

如果我在该列上创建索引,Postgres可以对该索引执行反向扫描以获取MAX()值。但是由于索引中除了一行之外的所有行都只是一个开销,我们可以在不创建完整索引的情况下获得相同的性能。

是的,可以创建一个触发器来更新跟踪MAX值的单行表,并查询该表而不是对主表发出MAX()。但我正在寻找一些优雅的东西,因为我知道Postgres有部分索引,而我似乎无法找到一种方法来为此目的利用它们。

更新:这个部分索引定义理想情况下是我想要的,但Postgres不允许部分索引的WHERE子句中的子查询。

create index on test(a) where a = (select max(a) from test);

2 个答案:

答案 0 :(得分:7)

不能predicate of a partial index中使用聚合函数或子查询表达式。无论如何,考虑到索引条目的IMMUTABLE性质,这在逻辑上几乎没有任何意义。

如果您有一系列整数,并且 保证 最大值始终大于x,您可以从此元信息中受益但是。

CREATE INDEX text_max_idx ON test (a) WHERE a > x;

如果包含与索引谓词匹配的WHERE子句,则此索引仅供查询计划程序使用。例如:

SELECT max(a) FROM test WHERE a > x;

可能有更多条件,但必须包含此条件才能使用索引 不过,我对“保证”很认真。如果谓词为false,则查询将不返回任何内容。

你可以构建一个故障安全:

SELECT COALESCE( (SELECT max(a) FROM test WHERE a > x)
                 (SELECT max(a) FROM test));

您可以使用多个部分索引来概括此方法。与this technique类似,只是很多更简单。

我会考虑触发方法,除了表上非常大的写入负载。

答案 1 :(得分:5)

索引中的其他行不是必需的,因为它们使您即使在删除的情况下也能保持最大准确度,或者在更新的情况下减少当前最大值。

如果您没有这样的操作(IOW最大值只会增加),您可以自己保持最大值。在应用程序代码或触发器中执行此操作。

Postgres无法知道最大值只会增加。它必须坚持删除和更新的能力。