2

PostgresにはUDFごとに複数の結果セットの機能があるようには見えないので(SQL Serverにはあります)。クエリ全体のシングルトン値を返すための最良の方法は何ですか?たとえば、FTS検索の結果をページ分割する場合、クエリに一致する結果の量を取得できれば(ページ付けを使用してすべてのページを反復処理する必要なしに)、ロジックが簡素化されます。

アプローチ1: SELECTリストにpost_countを貼り付けます。短所:重複

アプローチ2:別のUDFを記述してpost_countの短所を取得します:複数のUDF呼び出し(私はこのアプローチを使用し、最初のページを表示できるようにするためのレイテンシーを2倍にします)。

アプローチ3:結果セットに配列を使用し、post_countを結果セットの短所の兄弟として最上位に配置します:はるかに遅い-おそらくこれはarray_agg()関数によるものです(はい、私はこのアプローチを試しました)。

それで、この問題に対するより実用的な解決策はありますか?そうでない場合、これに対処するための開発パイプラインに何かがありますか?

4

1 に答える 1

1

私は自分でこの問題に繰り返し遭遇しましたが、1つの解決策を見つけられませんでした。

私の最新のアプローチは、返されたSETの最初の行をメタデータとして定義することでした。あなたはまだアプローチのリストにそれを持っていません。アプリケーションは最初の行を簿記に使用します。実際のデータは2行目から始まります。

明らかな弱点:メタデータに詰め込む必要のある行定義をすべて処理する必要があります。ただし、単純な合計数は、任意の数値または文字列タイプに適合します。
もちろん、アプリケーションの最初の行を特殊なケースにする必要があります。

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(ページサイズ)で帯域幅を節約できます。数行しかないため、オーバーヘッドの価値はほとんどありません。

別のアプローチは「アプローチ1」です-列を冗長に追加します

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 ()2番目のクエリの速度が低下するためです。だけで個別に実行するcount(*)方が高速です。

于 2012-09-05T18:19:25.910 に答える