Aus einem MySQL-Hintergrund, in dem die Leistung gespeicherter Prozeduren (älterer Artikel) und die Benutzerfreundlichkeit fraglich sind, bewerte ich PostgreSQL für ein neues Produkt für mein Unternehmen.
Ich möchte unter anderem einen Teil der Anwendungslogik in gespeicherte Prozeduren 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.
postgresql
best-practices
plpgsql
Derek Downey
quelle
quelle
Antworten:
Genau genommen verweist der Begriff "gespeicherte Prozeduren" auf SQL-Prozeduren in Postgres, die mit Postgres 11 eingeführt wurden.
Es gibt auch Funktionen , die fast dasselbe tun, aber nicht ganz dasselbe, und die waren von Anfang an dabei.
Funktionen mit
LANGUAGE sql
sind im Grunde genommen nur Batch-Dateien mit einfachen SQL-Befehlen in einem Funktionswrapper (und daher atomar, immer innerhalb einer einzelnen Transaktion ausgeführt), die Parameter akzeptieren. Alle Aussagen in einer SQL - Funktion sind geplant auf einmal , die von der Ausführung einer Anweisung nach dem anderen auf subtile Weise anders ist und die betreffen kann , in denen Schlösser getroffen werden.Für alles andere ist PL / pgSQL (
LANGUAGE plpgsql
) die ausgereifteste Sprache . Es funktioniert gut und wurde in den letzten zehn Jahren mit jeder Veröffentlichung verbessert, dient aber 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 verringert den Planungsaufwand und beschleunigt sie ein wenig als entsprechende SQL-Anweisungen. Dies kann je nach den Umständen einen spürbaren Effekt haben. Es kann auch Nebenwirkungen wie in dieser verwandten Frage haben:
Dies bringt die Vor- und Nachteile vorbereiteter Aussagen mit sich - wie im Handbuch erörtert . 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 für die angegebenen Parameter die Kosten für die Neuplanung überwiegt.Seit Postgres 9.2 werden generische Ausführungspläne immer noch für die Sitzung zwischengespeichert, jedoch unter Bezugnahme auf das Handbuch :
Wir bekommen die meiste Zeit das Beste aus beiden Welten (abzüglich einiger zusätzlicher Kosten), ohne (ab) zu verwenden
EXECUTE
. Details in Was ist neu in PostgreSQL 9.2 des PostgreSQL-Wikis .Postgres 12 führt die zusätzliche Servervariable ein
plan_cache_mode
, um generische oder benutzerdefinierte Pläne zu erzwingen. In besonderen Fällen ist Vorsicht geboten.Mit serverseitigen Funktionen, die verhindern , dass Ihre Anwendung zusätzliche Roundtrips zum Datenbankserver durchführt, können Sie große Gewinne erzielen . Lassen Sie den Server so oft wie möglich auf einmal ausführen und geben Sie nur ein genau definiertes Ergebnis zurück.
Vermeiden Sie die Verschachtelung komplexer Funktionen, insbesondere von Tabellenfunktionen (
RETURNING SETOF record
oderTABLE (...)
). Funktionen sind Black Boxes, die dem Abfrageplaner als Optimierungsbarrieren dienen. Sie werden separat optimiert, nicht im Zusammenhang mit der äußeren Abfrage, was die Planung vereinfacht, aber möglicherweise zu weniger als perfekten Plänen führt. Auch Kosten und Ergebnisgröße von Funktionen können nicht zuverlässig vorhergesagt werden.Die Ausnahme von dieser Regel sind einfache SQL-Funktionen (
LANGUAGE sql
), die - sofern bestimmte Voraussetzungen erfüllt sind - "inline" gesetzt werden können . Lesen Sie in dieser Präsentation von Neil Conway (Fortgeschrittene) mehr darüber, wie der Abfrageplaner funktioniert .In PostgreSQL wird eine Funktion immer automatisch in einer einzelnen Transaktion ausgeführt . Alles gelingt oder nichts. Wenn eine Ausnahme auftritt, wird alles zurückgesetzt. Aber es gibt eine Fehlerbehandlung ...
Das ist auch der Grund, warum Funktionen nicht genau "gespeicherte Prozeduren" sind (obwohl dieser Begriff manchmal irreführend verwendet wird). Einige Befehle wie
VACUUM
,CREATE INDEX CONCURRENTLY
oderCREATE DATABASE
können nicht in einem Transaktionsblock laufen, so dass sie in Funktionen nicht erlaubt. (Weder in SQL-Prozeduren noch in Postgres 11. Dies könnte später hinzugefügt werden.)Ich habe im Laufe der Jahre Tausende von plpgsql-Funktionen geschrieben.
quelle
Einige DO's:
quelle
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 zu 100% sicher), dass SQL-Sprachfunktionen schneller sind als diejenigen, die andere Sprachen verwenden, da sie keine Kontextumschaltung erfordern. Der Nachteil ist, dass keine prozedurale Logik erlaubt 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).
quelle
Sie können einige sehr interessante Dinge mit benutzerdefinierten Funktionen (UDF) in postgresql tun. Zum Beispiel gibt es Dutzende von möglichen Sprachen, die Sie verwenden können. Die integrierten Funktionen pl / sql und pl / pgsql sind sowohl fähig als auch zuverlässig und verwenden eine Sandbox-Methode, um Benutzer davon abzuhalten, allzu gefährliche Aktionen auszuführen. In C geschriebene UDFs bieten ein Höchstmaß an Leistung und Performance, da sie im selben Kontext wie die Datenbank selbst ausgeführt werden. Es ist jedoch so, als würde man mit dem Feuer spielen, denn selbst kleine Fehler können große Probleme verursachen, Backends stürzen ab oder Daten werden beschädigt. Mit den benutzerdefinierten pl-Sprachen wie pl / R, pl / ruby, pl / perl usw. können Sie sowohl Datenbank- als auch App-Layer in denselben Sprachen schreiben. Dies kann praktisch sein, da Sie keinen Perl-Programmierer Java oder pl / pgsql usw. unterrichten müssen, um eine UDF zu schreiben.
Schließlich gibt es noch die pl / proxy- Sprache. Mit dieser UDF-Sprache können Sie Ihre Anwendung für Skalierungszwecke auf Dutzenden oder mehr Back-End-Post-Gresql-Servern ausführen. Es wurde von den guten Leuten bei Skype entwickelt und ermöglicht im Grunde genommen die horizontale Skalierungslösung eines armen Mannes. Es ist überraschend einfach, auch darin 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, ist das Wichtigste, was Sie tun möchten, die Belastung der Datenbank so weit wie möglich zu reduzieren. UDFs, die die Datenmenge reduzieren, die aus der Datenbank in die Datenbank verschoben wird, tragen zur Reduzierung der E / A-Belastung bei. Wenn sie jedoch anfangen, die CPU-Auslastung zu erhöhen, können sie dann ein Problem darstellen. Im Allgemeinen hat die Reduzierung der E / A-Last oberste Priorität. Als Nächstes müssen Sie sicherstellen, dass die UDFs effizient sind, damit Ihre CPUs nicht überlastet werden.
quelle