This talk describes how somebody can write his or her own PostgreSQL custom aggregation functions.
Hans also shows, how to run windowing functions and analytics to handle data in PostgreSQL.
3. Worum es gehen wird
Wie funktionieren PostgreSQL Aggregates?
Wie kann man einfache Aggregates schreiben?
Wie können Windowing Functions optimiert werden?
Wie schreibt man Hypothetical Aggregates?
Hans-Jürgen Schönig
www.postgresql-support.de
4. Ein einfaches Aggregate
Ein Aggregate ist “etwas anders”
Eine “normale” Funktion gibt eine Zelle pro Aufruf retour
Ein Aggregate gibt eine Zeile pro Gruppe zurück
Hans-Jürgen Schönig
www.postgresql-support.de
5. Ein einfache Beispiele:
“Normale” Funktionen geben eine Zeile pro Aufruf zurück:
SELECT md5(x::text) FROM generate_series(1, 3) AS x;
md5
----------------------------------
c4ca4238a0b923820dcc509a6f75849b
c81e728d9d4c2f636f067f89cc14862c
eccbc87e4b5ce2fe28308fd9f2a7baf3
(3 rows)
Hans-Jürgen Schönig
www.postgresql-support.de
6. Einfache Beispiele:
Ein Aggregate macht aus vielen Zeilen eine Zeile:
SELECT sum(x) FROM generate_series(1, 3) AS x;
sum
-----
6
(1 row)
Hans-Jürgen Schönig
www.postgresql-support.de
8. Unser erstes Ziel
Wir beginnen mit einfachen Stringoperationen
Damit lässt sich der Workflow einfach verdeutlichen
Komplexere Prozesse laufen nach dem selben Schema
Hans-Jürgen Schönig
www.postgresql-support.de
9. Eine einfache Funktion
CREATE FUNCTION xagg(text, text) RETURNS text AS
$$
BEGIN
RAISE NOTICE 'xagg: "%" - adding %', $1, $2;
RETURN $1 || $2;
END;
$$ LANGUAGE 'plpgsql';
Hans-Jürgen Schönig
www.postgresql-support.de
10. Daraus kann man ein Aggregate machen
xagg wird für jede Zeile aufgerufen
CREATE AGGREGATE simpleagg(text) (
INITCOND = '',
SFUNC = xagg,
STYPE = text
);
Hans-Jürgen Schönig
www.postgresql-support.de
12. Kompliziertere Berechnungen
Zeilenoperationen reichen oft nicht aus
Um Berechnungen abzuschließen, kann eine FINALFUNC
definiert werden.
Beispiel: avg dividiert am Ende die Summe durch die Anzahl
Hans-Jürgen Schönig
www.postgresql-support.de
13. Eine einfache FINALFUNC
CREATE FUNCTION sample_final(text) RETURNS text AS
$$
SELECT $1 || 'X';
$$ LANGUAGE 'sql';
CREATE AGGREGATE simpleagg(text) (
INITCOND = '',
SFUNC = xagg,
FINALFUNC = sample_final,
STYPE = text
);
Hans-Jürgen Schönig
www.postgresql-support.de
16. Aggregate und Analytics
Alle Aggregate können auch als Windows verwendet werden
Effizienz kann bei komplexeren Frame Clauses ein Thema
werden
SELECT ...
OVER (ORDER BY ...
ROWS BETWEEN x PREDECING AND y FOLLOWING) ...
Hans-Jürgen Schönig
www.postgresql-support.de
17. Ein Beispiel für schlechte Performance (1):
test=# SELECT x, simpleagg(x::text)
OVER (ORDER BY x ROWS BETWEEN
3 PRECEDING AND 0 FOLLOWING )
FROM generate_series(1, 6) AS x;
NOTICE: xagg: "" - adding 1
NOTICE: xagg: "1" - adding 2
NOTICE: xagg: "12" - adding 3
NOTICE: xagg: "123" - adding 4
Hans-Jürgen Schönig
www.postgresql-support.de
19. Ein Beispiel für schlechte Performance (3):
x | simpleagg
---+-----------
1 | 1X
2 | 12X
3 | 123X
4 | 1234X
5 | 2345X
6 | 3456X
(6 rows)
=> Die Anzahl der Funktionsaufrufe ist explodiert
Hans-Jürgen Schönig
www.postgresql-support.de
20. Funktionsaufrufe reduzieren
Das Ziel ist, die Anzahl der Funktionsaufrufe zu reduzieren.
Transition Functions helfen in diesem Fall.
Transition Functions sind seit PostgreSQL 9.4 möglich
Hans-Jürgen Schönig
www.postgresql-support.de
21. Wie das funktioniert
Wir benötigen eine MSFUNC und eine MINVFUNC
CREATE FUNCTION x_msfunc(text, text) RETURNS text AS $$
BEGIN
RAISE NOTICE 'x_msfunc: % / %', $1, $2;
RETURN $1 || $2;
END;
$$ LANGUAGE 'plpgsql';
Hans-Jürgen Schönig
www.postgresql-support.de
22. Der zweite Teil des Aggregates
CREATE FUNCTION x_minvfunc(text, text) RETURNS text AS $$
BEGIN
RAISE NOTICE 'x_minvfunc: previous % / removing %',
$1, $2;
RETURN substring($1, 2, length($1) - 1);
END;
$$ LANGUAGE 'plpgsql';
Hans-Jürgen Schönig
www.postgresql-support.de
23. Das Aggregat definieren
CREATE AGGREGATE myagg(text) (
stype = text,
sfunc = xagg,
initcond = '',
msfunc = x_msfunc,
minvfunc = x_minvfunc,
mstype = text,
MINITCOND = ''
);
Die Logik ist sehr ähnlich wie vorher
Eine der Funktionen wird für jede Zeile aufgerufen.
Ein optionaler Funktionsaufruf passiert am Ende.
Hans-Jürgen Schönig
www.postgresql-support.de
24. Eine Demo-Abfrage
SELECT x, myagg(x::text) OVER (
PARTITION BY x % 2 ORDER BY x::text
ROWS BETWEEN CURRENT ROW AND 2 FOLLOWING)
FROM generate_series(1, 9) AS x
ORDER BY x;
Hans-Jürgen Schönig
www.postgresql-support.de
29. Was sind Hypothetical Aggregates?
Hypothetical Aggregates beantworten die “what if” Frage
Wie wäre das Ergebnis, würde ein bestimmter Wert existieren?
Ein klassisches Beispiel:
test=# SELECT x % 2 AS odd_even,
rank(5) WITHIN GROUP (ORDER BY x)
FROM generate_series(1, 10) AS x
GROUP BY 1;
odd_even | rank
----------+------
0 | 3
1 | 3
(2 rows)
Hans-Jürgen Schönig
www.postgresql-support.de
31. Weitere Funktionen werden benötigt
Wieder benötigen wir eine SFUNC:
CREATE FUNCTION hypo_sfunc(text, text) RETURNS text AS
$$
BEGIN
RAISE NOTICE 'hypo_sfunc: % / %', $1, $2;
RETURN $1 || $2;
END;
$$ LANGUAGE 'plpgsql';
Hans-Jürgen Schönig
www.postgresql-support.de
32. Eine FINALFUNC
Eine Funktion wird wieder am Ende aufgerufen
CREATE FUNCTION hypo_final(text, text, text)
RETURNS text AS
$$
BEGIN
RAISE NOTICE 'hypo_final: % / % / %', $1, $2, $3;
RETURN $1 || $2;
END;
$$ LANGUAGE 'plpgsql';
Hans-Jürgen Schönig
www.postgresql-support.de
33. Die Definition des Aggregates
CREATE AGGREGATE whatif(text ORDER BY text) (
INITCOND = '',
STYPE = text,
SFUNC = hypo_sfunc,
FINALFUNC = hypo_final,
FINALFUNC_EXTRA = true,
HYPOTHETICAL
);
Hans-Jürgen Schönig
www.postgresql-support.de
34. Ein Beispiel
SELECT (x % 2)::text, whatif('abc')
WITHIN GROUP (ORDER BY x::text )
FROM generate_series(1, 4) AS x
GROUP BY 1;
Hans-Jürgen Schönig
www.postgresql-support.de