Skip to content

SQLAlchemy "default" vs. "server_default" Leistung

Wir geben Ihnen die Lösung für dieses Problem, oder zumindest glauben wir das. Wenn Sie Bedenken haben, teilen Sie uns dies unverzüglich mit

Lösung:

Es ist unmöglich, Ihnen eine Antwort zu geben, die besagt, dass dies schneller ist, da die Leistung per Standardwertausdruck sehr unterschiedlich sein kann, sowohl auf dem Server als auch in Python. Eine Funktion zum Abrufen der aktuellen Zeit verhält sich anders als ein skalarer Standardwert.

Als Nächstes müssen Sie erkennen, dass Standardwerte in fünf . verschiedene Arten:

  • Client-seitige skalare Standardwerte. Ein fester Wert, wie ein 0 oder . True. Der Wert wird in einer INSERT Anweisung verwendet.
  • Client-seitige Python-Funktion. Wird jedes Mal aufgerufen, wenn ein Standardwert benötigt wird, und erzeugt den einzufügenden Wert, der von da an wie ein skalarer Standardwert verwendet wird. Diese können kontextsensitiv sein (haben Zugriff auf den aktuellen Ausführungskontext mit einzufügenden Werten).
  • Client-seitiger SQL-Ausdruck; dieser erzeugt einen zusätzlichen SQL-Ausdruck, der dann in der Abfrage verwendet und auf dem Server ausgeführt wird, um einen Wert zu erzeugen.
  • Serverseitige DLL-Ausdrücke sind SQL-Ausdrücke, die dann in der Tabellendefinition gespeichert werden, also Teil des Schemas sind. Der Server verwendet diese, um einen Wert für alle Spalten zu füllen, die in INSERT Anweisungen, oder wenn ein Spaltenwert auf DEFAULT in einer INSERT oder UPDATE Anweisung.
  • Serverseitige implizite Standardwerte oder Trigger, bei denen andere DLL wie Trigger oder spezifische Datenbankfunktionen einen Standardwert für Spalten bereitstellen.

Wenn ein SQL-Ausdruck den Standardwert bestimmt, egal ob es sich um einen clientseitigen SQL-Ausdruck, einen serverseitigen DLL-Ausdruck oder einen Trigger handelt, macht es für eine Datenbank kaum einen Unterschied, woher der Standardwert-Ausdruck stammt. Der Query Executor muss wissen, wie er Werte für eine bestimmte Spalte erzeugen kann. Sobald das aus der DML-Anweisung oder der Schemadefinition herausgelesen wurde, muss der Server den Ausdruck für jede Zeile ausführen.

Die Wahl zwischen diesen Optionen wird selten allein auf der Leistung beruhen, die Leistung sollte höchstens nur einer von mehreren Aspekten sein, die Sie berücksichtigen. Es gibt viele Faktoren, die hier eine Rolle spielen:

  • default mit einem Skalar oder einer Python-Funktion erzeugt direkt einen Python-Standardwert und sendet dann beim Einfügen den neuen Wert an den Server. Python-Code kann auf den Standardwert zugreifen, bevor die Daten in die Datenbank eingefügt werden.
  • Ein Client-seitiger SQL-Ausdruck, ein server_default Wert und serverseitige implizite Standardwerte und Trigger lassen den Server den Standardwert generieren, der dann vom Client abgerufen werden muss, wenn man in der gleichen SQLAlchemy-Sitzung darauf zugreifen möchte. Der Zugriff auf den Wert ist erst möglich, wenn das Objekt in die Datenbank eingefügt wurde.

    Abhängig von der genauen Abfrage und der Datenbankunterstützung, muss SQLAlchemy möglicherweise extra SQL-Abfragen machen, um entweder einen Standard vor der INSERT Anweisung oder eine separate SELECT Anweisung auszuführen, um die eingefügten Standardwerte abzurufen. Sie können steuern, wann dies geschieht (direkt beim Einfügen oder beim ersten Zugriff nach dem Flushing, mit der eager_defaults Mapper-Konfiguration).

  • Wenn Sie mehrere Clients auf verschiedenen Plattformen haben, die auf dieselbe Datenbank zugreifen, kann ein server_default oder eine andere Vorgabe, die an das Schema angehängt ist (z. B. ein Trigger), stellt sicher, dass alle Clients unabhängig davon dieselben Vorgaben verwenden, während in Python implementierte Vorgaben von anderen Plattformen nicht erreicht werden können.

Wenn PostgreSQL verwendet wird, kann SQLAlchemy die RETURNING Klausel für DML-Anweisungen verwenden, wodurch ein Client in einem einzigen Schritt Zugriff auf serverseitig generierte Vorgaben erhält.

Wenn Sie also eine server_default Spaltenvorgabe, die für jede Zeile einen neuen Wert berechnet (keinen skalaren Wert), spart man auf der Python-Seite ein wenig Zeit und spart ein wenig Netzwerkbandbreite, da man keine Daten für diese Spalte an die Datenbank sendet. Die Datenbank könnte schneller sein, denselben Wert zu erzeugen, oder sie könnte langsamer sein; das hängt weitgehend von der Art der Operation ab. Wenn Sie in derselben Transaktion Zugriff auf den generierten Standardwert aus Python benötigen, müssen Sie auf einen von SQLAlchemy geparsten Rückgabestrom von Daten warten. Alle diese Details kann im Vergleich zu allem anderen, was beim Einfügen oder Aktualisieren von Zeilen passiert, unbedeutend werden.

Man muss verstehen, dass ein ORM nicht für hochperformante Masseneinfügungen oder -aktualisierungen von Zeilen geeignet ist. Zitat aus der SQAlchemy Leistung FAQ-Eintrag:

Der SQLAlchemy ORM verwendet bei der Synchronisierung von Änderungen an der Datenbank das Unit-of-Work-Muster. Dieses Muster geht weit über das einfache "Einfügen" von Daten hinaus. Es beinhaltet, dass Attribute, die Objekten zugewiesen werden, mit Hilfe eines Attribut-Instrumentierungssystems empfangen werden, das Änderungen an Objekten verfolgt, während sie vorgenommen werden, es beinhaltet, dass alle eingefügten Zeilen in einer Identitätskarte verfolgt werden, was zur Folge hat, dass SQLAlchemy für jede Zeile ihre "zuletzt eingefügte ID" abrufen muss, wenn sie nicht bereits gegeben ist, und es beinhaltet auch, dass einzufügende Zeilen bei Bedarf nach Abhängigkeiten durchsucht und sortiert werden. Objekte unterliegen auch einem gewissen Maß an Buchhaltung, um all dies am Laufen zu halten, was bei einer sehr großen Anzahl von Zeilen auf einmal zu einem unangemessenen Zeitaufwand für große Datenstrukturen führen kann, weshalb es am besten ist, diese zu zerlegen.

Im Grunde ist Unit of Work ein hohes Maß an Automatisierung, um die Aufgabe der Persistierung eines komplexen Objektgraphen in eine relationale Datenbank ohne expliziten Persistenzcode zu automatisieren, und diese Automatisierung hat ihren Preis.

ORMs sind grundsätzlich nicht für hochperformante Bulk-Inserts gedacht - das ist der ganze Grund, warum SQLAlchemy den Core zusätzlich zum ORM als erstklassige Komponente anbietet.

Da ein ORM wie SQLAlchemy mit einem hohen Overhead-Preis verbunden ist, verschwinden Leistungsunterschiede zwischen einem serverseitigen und einem Python-seitigen Standard schnell im Rauschen der ORM-Operationen.

Wenn Sie sich also Sorgen um die Leistung bei Einfüge- oder Aktualisierungsvorgängen für große Mengen machen, sollten Sie Bulk-Operationen für diese verwenden und die Option psycopg2 Batch-Ausführungshilfen aktivieren, um wirklich einen Geschwindigkeitsschub zu erhalten. Wenn Sie diese Bulk-Operationen verwenden, erwarte ich, dass die serverseitigen Standardwerte die Leistung verbessern, indem sie einfach Bandbreite für die Übertragung von Zeilendaten von Python zum Server einsparen, aber wie viel, hängt von der genauen Art der Standardwerte ab.

Wenn die ORM-Einfüge- und Aktualisierungsleistung außerhalb von Massenoperationen für Sie ein großes Problem darstellt, müssen Sie Ihre spezifischen Optionen testen. Ich würde mit der SQLAlchemy beginnen examples.performance Paket und fügen Sie Ihre eigene Testsuite hinzu, indem Sie zwei Modelle verwenden, die sich nur in einem einzigen server_default und default Konfiguration unterscheiden.

Es gibt noch etwas anderes Wichtiges, als nur die Leistung der beiden zu vergleichen

Wenn Sie eine neue Spalte hinzufügen müssten create_at (Not Null) zu einer bestehenden Tabelle User mit einigen Daten darin, default wird nicht funktionieren.

Wenn verwendet defaultverwendet wird, tritt bei der Aktualisierung der Datenbank die Fehlermeldung auf, dass kein Nullwert in vorhandene Daten in der Tabelle eingefügt werden kann. Dies führt zu erheblichen Problemen, wenn Sie Ihre Daten beibehalten wollen, und sei es nur zu Testzwecken.

Und bei Verwendung von server_defaultverwendet wird, fügt die Datenbank während des Upgrades der DB den aktuellen DateTime-Wert in alle zuvor vorhandenen Testdaten ein.

In diesem Fall wird also nur server_default funktionieren.



Nutzen Sie unsere Suchmaschine

Suche
Generic filters

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht.