2012-09-05 22 views
2

由於Postgres對於每個UDF(SQL Server does)似乎沒有多個結果集的功能。什麼是返回查詢範圍內的單值的最佳方式?例如,當對FTS搜索的結果進行分頁時,如果我們可以獲得與查詢相匹配的結果數量(無需使用分頁對所有頁面進行迭代),則可以簡化邏輯。使用Postgres返回單個查詢的值

方法一:將post_count粘在SELECT列表中。缺點:重複

方法有兩個:寫一個單獨的UDF獲得POST_COUNT缺點:多個UDF調用(我使用這種方法,它雙打能夠呈現的第一頁的等待時間)。

方法三:使用數組結果集,並把POST_COUNT在頂層作爲同級的結果集的缺點:慢得多 - 這也許是由於array_agg()功能(是的,我試過這種方法)。

那麼是否有更實用的解決方案來解決這個問題?如果不是的話,是否有什麼東西可以解決這個問題?

+0

*請停止創建'postgres-9.1'標籤。 'postgresql-9.1'存在,並且是正確的引導拼寫。 – Charles

+0

問題是PostgreSQL有*函數*而不是*存儲過程*。最接近你可以進入一個函數的是返回一個'SETUP refcursor',但你仍然需要通過光標並顯示結果;如果這是另一個功能,那麼你又回到了同一條船上。開發人員一直在思考如何提供存儲過程(除了函數),但是還有一些技術問題與事務管理有關,這些問題還沒有被整理出來。 – kgrittn

+0

@kgrittn可能會混淆錯字;這將是'SETOF refcursor'而不是'SETUP refcursor'' –

回答

1

我一再遇到這個問題,並沒有找到一個的解決方案。

我最近的做法是將返回的SET的第一行定義爲元數據,即第一個行。你的方法列表中沒有那個。 應用程序使用第一行進行簿記。實際數據從第二行開始。

一個明顯的缺點:你必須處理你的元數據中必須擠壓的任何行定義。不過,一個簡單的總數將適用於任何數字或字符串類型。
當然,您必須特別處理應用程序中的第一行。

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; 

呼叫:

這個簡單的例子從定義的表foo作爲

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

頁尺寸是20行,在函數頭部每默認預設返回行

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()減慢了第二個查詢。一個單獨的運行只有count(*)更快。