![](https://habrastorage.org/storage2/72f/8c3/233/72f8c32332e47ce12b30d3c4b88f17ae.gif)
誰が、なぜ変なものが欲しいのでしょうか? さて、昼夜を問わずいくつかのWebサーバーを監視し、1時間ごとの稼働時間を把握したいとします。 サーバーのステータスが30秒ごとにテーブルに入力されるとします。TRUE-サーバーは実行中、 FALSE-サーバーは横になっています。 その後、ほとんどの時間サーバーが動作していた場合はTRUEを返し、ほとんどの場合サーバーが立っていた場合はFALSEを返します 。 監視システム自体が嘘をついているため、データがない場合、 NULLを返します 。
もちろん、これはすべて、 WINDOWメカニズムなど、他のさまざまなメカニズムを使用して実行できます。 ただし、あるリクエストでは、ダウンタイムやサーバー操作など、他の蓄積された統計を処理する必要があると想像してください。 この場合、PostgreSQLはエレガントなメカニズムを提供します。
まず、ブールフィールドに関するデータを蓄積する統計関数が必要です。 通常、このような関数には2つの入力パラメーターがあります。
- 計算された値が保存されるパラメーター(結局、この関数は行ごとに呼び出されます);
- 現在の行の値が入る列の型パラメーター。
サーバーのUPおよびDOWN測定値の数を保存するとします。 これには整数配列を使用できます。 同じ成功で、これは複合型で行うことができます。 翻訳者 。 このような関数は、純粋なSQLでも簡単に記述できます。
CREATE OR REPLACE function mode_bool_state(int[], boolean) RETURNS int[] LANGUAGE sql as $body$ SELECT CASE $2 WHEN TRUE THEN array[ $1[1] + 1, $1[2] ] WHEN FALSE THEN array[ $1[1], $1[2] + 1 ] ELSE $1 END; $body$;
int []関数の結果は、次の行で呼び出されるとき、同じ関数の入力への最初のパラメーターとして提供されることに注意してください。 翻訳者 。
決定を下して最終結果を出力するには、別の関数を作成します。
CREATE OR REPLACE FUNCTION mode_bool_final(INT[]) RETURNS boolean LANGUAGE sql as $body$ SELECT CASE WHEN ( $1[1] = 0 AND $1[2] = 0 ) THEN NULL ELSE $1[1] >= $1[2] END; $body$;
ポイントは小さいです-ユニットを宣言します:
CREATE AGGREGATE mode(boolean) ( SFUNC = mode_bool_state, STYPE = INT[], FINALFUNC = mode_bool_final, INITCOND = '{0,0}' );
ここで、 SFUNCとFINALFUNCは関数の名前、 STYPEは統計を収集するためのデータ型、 INITCONDは初期条件です。
仕組みを見てみましょう!
SELECT server_name, sum(CASE WHEN server_up THEN 0.5 ELSE 0 END) as minutes_up, mode(server_up) as mode FROM servers WHERE montime BETWEEN '2013-04-01' and '2013-04-01 01:00:00';
server_name minutes_upモード web1 56.5 TRUE web2 0.0 FALSE web3 48.0 TRUE web4 11.5 FALSE
PSトムブラウンによる英語の記事も、カスタム集計の作成方法を説明しています。 その中で、作者は最後のオプションのFINALFUNC関数を使用しません。彼の例でSTYPEデータを収集するためのタイプは、集約の基本タイプと同じだからです。