分区表上的高效最小值/最大值
来自 PostgreSQL wiki
跳转到导航跳转到搜索
PostgreSQL 9.0 及更早版本不支持对分区/继承表进行索引的 MIN(x) 或 MAX(x) 查询。查看 MAX Partitioning with MIN Pain,以了解展示问题的测试案例,以及从 PostgreSQL 9.1 开始如何解决此问题。但是,在早期版本中,可以使用自定义 PL/pgSQL 函数来高效地实现这一点。
此代码片段由 Shaun Thomas 在 pgsql-performance 邮件列表中 贡献,并在其他人的反馈下进行了调整。该函数的原始版本适用于 PostgreSQL 8.2,并且可能适用于使用该版本的用户。由于使用了该版本中引入的 regclass 功能,因此此处简化的版本仅与 PostgreSQL 8.3 及更高版本兼容。
此函数适用于 bigint(以及整数/小整数)列并使用 MAX() 聚合。将其移植到其他数据类型或使其与 min() 一起使用并不困难。
函数定义
/**
* Return the Maximum bigint Value for a Partitioned Table Column
*
* @param string Name of table, may be schema-qualified.
* @param string Name of column to search.
*/
CREATE OR REPLACE FUNCTION spc_max_part_int(rParent regclass, sColName text)
RETURNS bigint AS
$$
DECLARE
rChild regclass;
nMax bigint;
nTemp bigint;
BEGIN
EXECUTE '
SELECT max(' || quote_ident(sColName) ||')
FROM ONLY ' || rParent
INTO nMax;
FOR rChild IN
SELECT inhrelid
FROM pg_inherits
WHERE inhparent=rParent
LOOP
nTemp := spc_max_part_int(rChild, sColName);
nMax := greatest(nTemp, nMax);
END LOOP;
RETURN nMax;
END;
$$ LANGUAGE plpgsql STABLE;
示例用法
db=> explain select max(foo_id) from foo;
QUERY PLAN
--------------------------------------------------------------------------------------
Aggregate (cost=177032.00..177032.01 rows=1 width=4)
-> Append (cost=0.00..150477.20 rows=10621920 width=4)
-> Seq Scan on foo (cost=0.00..34.00 rows=2400 width=4)
-> Seq Scan on foo_child1 foo (cost=0.00..150443.20 rows=10619520 width=4)
db=> select max(foo_id) from foo;
max
----------
10000000
Time: 2636.540 ms
db=> select spc_max_part_int('foo', 'foo_id');
spc_max_part_int
------------------
10000000
Time: 0.556 ms