6

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

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

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

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

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

4

2 回答 2

8

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

如果你有一个整数范围,并且你可以保证最大值总是大于x,那么你可以从这个元信息中受益。

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

WHERE只有当您包含与索引谓词匹配的子句时,查询计划程序才会使用此索引。例如:

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

可以有更多条件,但必须包含这个条件才能使用索引。
不过,我对“保证”是认真的。如果谓词为假,您的查询将不返回任何内容。

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

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

您可以使用多个部分索引来概括此方法。类似于这种技术,只是简单得多。

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

于 2013-07-24T17:59:28.100 回答
6

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

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

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

于 2013-07-24T19:14:00.323 回答