it-swarm.com.de

Funktionsleistung

Aus einem MySQL-Hintergrund stammend, in dem gespeicherte Prozeduren Leistung (älterer Artikel) und Benutzerfreundlichkeit fraglich sind, evaluiere ich PostgreSQL für ein neues Produkt für mein Unternehmen.

Eines der Dinge, die ich tun möchte, ist, einige der Anwendungslogik in gespeicherte Prozeduren zu verschieben, daher frage ich hier nach DOs und DON'Ts (Best Practices) für die Verwendung von Funktionen in PostgreSQL (9.0) ), insbesondere in Bezug auf Leistungsprobleme.

53
Derek Downey

Genau genommen verweist der Begriff "gespeicherte Prozeduren" auf SQL-Prozeduren in Postgres, eingeführt mit Postgres 11. Verwandte Themen:

Es gibt auch Funktionen, die fast, aber nicht ganz dasselbe tun, und diese waren von Anfang an dabei.

Funktionen mit LANGUAGE sql Sind im Grunde nur Batch-Dateien mit einfachen SQL-Befehlen in einem Funktions-Wrapper (und daher atomar, werden immer in einem single ausgeführt Transaktion) Parameter akzeptieren. Alle Anweisungen in einer SQL-Funktion sind geplant sofort, was sich geringfügig von der Ausführung einer Anweisung nach der anderen unterscheidet, und kann sich auf die Reihenfolge auswirken, in der Sperren ausgeführt werden.

Für alles andere ist die ausgereifteste Sprache PL/pgSQL (LANGUAGE plpgsql). Es funktioniert gut und wurde mit jeder Version im letzten Jahrzehnt verbessert, dient jedoch am besten als Klebstoff für SQL-Befehle. Es ist nicht für umfangreiche Berechnungen gedacht (außer bei SQL-Befehlen).

PL/pgSQL-Funktionen führen Abfragen wie vorbereitete Anweisungen aus. Die Wiederverwendung von zwischengespeicherten Abfrageplänen reduziert den Planungsaufwand und macht sie etwas schneller als entsprechende SQL-Anweisungen, was je nach den Umständen spürbare Auswirkungen haben kann. Es kann auch Nebenwirkungen wie in dieser verwandten Frage haben:

Dies bringt die Vor- und Nachteile vorbereiteter Aussagen mit sich - wie im Handbuch beschrieben . Bei Abfragen in Tabellen mit unregelmäßiger Datenverteilung und variierenden Parametern kann dynamisches SQL mit EXECUTE eine bessere Leistung erzielen, wenn der Gewinn aus einem optimierten Ausführungsplan erzielt wird für die angegebenen Parameter überwiegen die Kosten für die Neuplanung.

Da Postgres 9.2 generische Ausführungspläne für die Sitzung noch zwischengespeichert werden, aber zitiert das Handbuch :

Dies tritt sofort für vorbereitete Anweisungen ohne Parameter auf; Andernfalls tritt es erst auf, nachdem fünf oder mehr Ausführungen Pläne erstellt haben, deren geschätzter Kostendurchschnitt (einschließlich Planungsaufwand) teurer ist als die allgemeine Plankostenschätzung.

Wir bekommen das Beste aus beiden Welten meistens (abzüglich eines zusätzlichen Overheads) ohne (ab) mit EXECUTE. Details in Was ist neu in PostgreSQL 9.2 des PostgreSQL-Wikis .

Postgres 12 führt die zusätzliche Servervariable plan_cache_mode ein, um generische oder benutzerdefinierte Pläne zu erzwingen. In besonderen Fällen vorsichtig verwenden.

Sie können große mit serverseitigen Funktionen gewinnen, die zusätzliche Roundtrips von Ihrer Anwendung zum Datenbankserver verhindern. Lassen Sie den Server so viel wie möglich gleichzeitig ausführen und geben Sie nur ein genau definiertes Ergebnis zurück.

Vermeiden Sie das Verschachteln komplexer Funktionen, insbesondere von Tabellenfunktionen (RETURNING SETOF record Oder TABLE (...)). Funktionen sind Black Boxes, die als Optimierungsbarrieren für den Abfrageplaner dienen. Sie werden separat optimiert, nicht im Kontext der äußeren Abfrage, was die Planung vereinfacht, aber möglicherweise zu weniger als perfekten Plänen führt. Außerdem können Kosten und Ergebnisgröße von Funktionen nicht zuverlässig vorhergesagt werden.

Die Ausnahme zu dieser Regel sind einfache SQL-Funktionen (LANGUAGE sql), Die "inlined" - falls vorhanden sein können Voraussetzungen sind erfüllt . Lesen Sie hier mehr darüber, wie der Abfrageplaner funktioniert Präsentation von Neil Conway (fortgeschrittenes Material).

In PostgreSQL wird eine Funktion immer automatisch innerhalb einer einzelnen Transaktion ausgeführt. Alles gelingt oder nichts. Wenn eine Ausnahme auftritt, wird alles zurückgesetzt. Aber es gibt Fehlerbehandlung ...

Das ist auch der Grund, warum Funktionen nicht ​​ genau "gespeicherte Prozeduren" sind (obwohl dieser Begriff manchmal verwendet wird irreführend). Einige Befehle wie VACUUM , CREATE INDEX CONCURRENTLY oder CREATE DATABASE können nicht in einem Transaktionsblock ausgeführt werden , also sind sie in Funktionen nicht erlaubt. (Noch nicht in SQL-Prozeduren ab Postgres 11. Dies kann später hinzugefügt werden.)

Ich habe im Laufe der Jahre Tausende von plpgsql-Funktionen geschrieben.

55

Einige DOs:

  • Verwenden Sie nach Möglichkeit SQL als Funktionssprache, da PG die Anweisungen einbinden kann
  • Verwenden Sie IMMUTABLE/STABLE/VOLATILE korrekt, da PG Ergebnisse zwischenspeichern kann, wenn es unveränderlich oder stabil ist
  • Verwenden Sie STRICT korrekt, da PG nur null zurückgeben kann, wenn eine Eingabe null ist, anstatt die Funktion auszuführen
  • Ziehen Sie PL/V8 in Betracht, wenn Sie SQL nicht als Funktionssprache verwenden können. Es ist schneller als PL/pgSQL in einigen unwissenschaftlichen Tests, die ich durchgeführt habe
  • Verwenden Sie LISTEN/NOTIFY für länger laufende Prozesse, die außerhalb der Transaktion auftreten können
  • Erwägen Sie die Verwendung von Funktionen zum Implementieren der Paginierung, da die schlüsselbasierte Paginierung schneller sein kann als die LIMIT-basierte Paginierung
  • Stellen Sie sicher, dass Sie Ihre Funktionen einem Unit-Test unterziehen
12
Neil McGuigan

Im Allgemeinen bedeutet das Verschieben der Anwendungslogik in die Datenbank, dass sie schneller ist - schließlich wird sie näher an den Daten ausgeführt.

Ich glaube (bin mir aber nicht 100% sicher), dass SQL-Sprachfunktionen schneller sind als diejenigen, die andere Sprachen verwenden, da sie keinen Kontextwechsel erfordern. Der Nachteil ist, dass keine prozedurale Logik zulässig ist.

PL/pgSQL ist die ausgereifteste und funktionsreichste der integrierten Sprachen - aber für die Leistung kann C verwendet werden ( obwohl es nur rechenintensiven Funktionen zugute kommt)

Mit benutzerdefinierten Funktionen (UDF) in postgresql können Sie einige sehr interessante Dinge tun. Zum Beispiel gibt es Dutzende von möglichen Sprachen, die Sie verwenden können. Die integrierten pl/sql und pl/pgsql sind sowohl leistungsfähig als auch zuverlässig und verwenden eine Sandbox-Methode, um Benutzer davon abzuhalten, etwas zu schrecklich Gefährliches zu tun. In C geschriebene UDFs bieten Ihnen ein Höchstmaß an Leistung und Leistung, da sie im selben Kontext wie die Datenbank selbst ausgeführt werden. Es ist jedoch wie mit dem Feuer zu spielen, da selbst kleine Fehler große Probleme verursachen können, Backends abstürzen oder Daten beschädigt werden. Die benutzerdefinierten pl-Sprachen wie pl/R, pl/Ruby, pl/Perl usw. bieten Ihnen die Möglichkeit, sowohl Datenbank- als auch App-Ebenen in denselben Sprachen zu schreiben. Dies kann nützlich sein, da Sie keinen Perl-Programmierer unterrichten müssen Java oder pl/pgsql usw., um eine UDF zu schreiben.

Schließlich gibt es die Sprache pl/proxy . Mit dieser UDF-Sprache können Sie Ihre Anwendung für Skalierungszwecke auf Dutzenden oder mehr Postgresql-Backend-Servern ausführen. Es wurde von den guten Leuten bei Skype entwickelt und ermöglicht im Grunde die horizontale Skalierungslösung eines armen Mannes. Es ist überraschend einfach, auch zu schreiben.

Nun zum Leistungsproblem. Dies ist eine Grauzone. Schreiben Sie eine App für eine Person? Oder für 1.000? oder für 10.000.000? Die Art und Weise, wie Sie Ihre App erstellen und UDFs verwenden, hängt stark davon ab, wie Sie skalieren möchten. Wenn Sie für Tausende und Abertausende von Benutzern schreiben, möchten Sie vor allem die Belastung der Datenbank so weit wie möglich reduzieren. UDFs, die die Datenmenge reduzieren, die in die Datenbank verschoben und zurück in die Datenbank verschoben wird, tragen zur Reduzierung der Last bei IO. Wenn sie jedoch die CPU-Last erhöhen), können sie dann ein Problem darstellen IO Laden ist die erste Priorität, und als nächstes müssen Sie sicherstellen, dass die UDFs effizient sind, um Ihre CPUs nicht zu überlasten.

7
Scott Marlowe