2

由于 Postgres 似乎没有每个 UDF 的多个结果集的功能(SQL Server 有)。返回查询范围的单例值的最佳方法是什么?例如,在对 FTS 搜索的结果进行分页时,如果我们可以获得与查询匹配的结果数量(无需使用分页遍历所有页面),它会简化逻辑。

方法一:将 post_count 粘贴在 SELECT 列表中。缺点:重复

方法二:编写一个单独的 UDF 来获取 post_count 缺点:多个 UDF 调用(我使用这种方法,它使能够呈现第一页的延迟加倍)。

方法三:对结果集使用数组,并将 post_count 作为结果集的兄弟放在顶层 缺点:慢得多 - 也许这是由于array_agg()函数(是的,我尝试了这种方法)。

那么这个问题是否有更务实的解决方案,如果没有,开发流程中是否有任何东西可以解决这个问题?

4

1 回答 1

1

我自己反复遇到这个问题,并没有找到一个解决方案。

我最新的方法是将返回的 SET 的第一行定义为元数据。您的方法列表中还没有那个。该应用程序使用第一行进行簿记。实际数据从第二行开始。

明显的弱点:您必须处理必须压缩到元数据中的任何行定义。不过,一个简单的总数将适合任何数字或字符串类型。
当然,您必须对应用程序中的第一行进行特殊处理。

foo这个简单的示例从定义为的表中返回行

CREATE TABLE foo (
  foo_id serial PRIMARY KEY
 ,foo    text
 );

页面大小为 20 行,默认在函数标题中预设:

CREATE OR REPLACE FUNCTION f_paginate(_max_id int, _limit int = 20
                                                 , _offset int = 0)
  RETURNS TABLE(foo_id int, foo text) AS
$BODY$
BEGIN

SELECT INTO foo_id  count(*)::int
FROM   foo f
WHERE  f.foo_id < _max_id; -- get count

RETURN NEXT;               -- use first row for meta-data

RETURN QUERY               -- actual data starts with second row
SELECT f.foo_id, f.foo
FROM   foo f
WHERE  f.foo_id < _max_id
LIMIT  _limit
OFFSET _offset;

END;
$BODY$
  LANGUAGE plpgsql;

称呼:

SELECT * FROM f_paginate(100);

回报:

foo_id | foo
-------+----
86     | <NULL>    <-- first row = meta-data
1      | bar       <-- actual data
2      | baz
... 18 more ...

显然这种方法可以通过更高的_limit(页面大小)节省一些带宽。只有几行,几乎不值得开销。

另一种方法是您的“方法一” - 冗余添加一列

CREATE OR REPLACE FUNCTION f_paginate2(_max_id int, _limit int = 20
                                                  , _offset int = 0)
  RETURNS TABLE(foo_id int, foo text, ct bigint) AS
$BODY$
BEGIN

RETURN QUERY
SELECT f.foo_id, f.foo, count(*) OVER ()
FROM   foo f
WHERE  f.foo_id < _max_id
LIMIT  _limit
OFFSET _offset;

END;
$BODY$
  LANGUAGE plpgsql VOLATILE;

称呼:

SELECT * FROM f_paginate2(100);

回报:

foo_id | foo | ct
-------+-----+----
1      | bar | 86
2      | baz | 86
... 18 more ...

在这个简单的情况下,性能非常相似。第一个查询稍微快一点,但可能只是因为count(*) OVER ()减慢了第二个查询。单独运行 justcount(*)更快。

于 2012-09-05T18:19:25.910 回答