shopkeeper
Tabelle enthält folgende Felder:
id (bigint),amount (numeric(19,2)),createddate (timestamp)
Angenommen, ich habe die obige Tabelle. Ich möchte die Aufzeichnungen für gestern abrufen und einen Bericht erstellen, indem der Betrag in Cent gedruckt wird.
Eine Möglichkeit besteht darin, Berechnungen in meiner Java-Anwendung durchzuführen und eine einfache Abfrage auszuführen
Date previousDate ;// $1 calculate in application
Date todayDate;// $2 calculate in application
select amount where createddate between $1 and $2
und dann die Datensätze durchlaufen und den Betrag in meiner Java-Anwendung in Cent umrechnen und den Bericht generieren
Eine andere Möglichkeit besteht darin, Berechnungen in der SQL-Abfrage selbst durchzuführen:
select cast(amount * 100 as int) as "Cents"
from shopkeeper where createddate between date_trunc('day', now()) - interval '1 day' and date_trunc('day', now())
Führen Sie dann eine Schleife durch die Datensätze und generieren Sie den Bericht
In einer Weise wird meine gesamte Verarbeitung in einer Java-Anwendung ausgeführt und eine einfache Abfrage wird ausgelöst. In anderen Fällen werden alle Konvertierungen und Berechnungen in einer SQL-Abfrage durchgeführt.
Der obige Anwendungsfall ist nur ein Beispiel. In einem realen Szenario kann eine Tabelle viele Spalten enthalten, die eine Verarbeitung ähnlicher Art erfordern.
Können Sie mir bitte sagen, welcher Ansatz in Bezug auf Leistung und andere Aspekte besser ist und warum?
quelle
Antworten:
Es hängt von vielen Faktoren ab - aber am wichtigsten:
Wie immer, wenn Sie tun die Daten zurück an den App-Server bringen, minimiert die Spalten und Zeilen werden zu Ihrem Vorteil sein. Wenn Sie sicherstellen, dass die Abfrage optimiert und entsprechend indiziert ist, können Sie beide Szenarien unterstützen.
Zu Ihrer Notiz:
Das Durchlaufen von Datensätzen ist in SQL fast immer das Falsche - das Schreiben einer satzbasierten Operation wird bevorzugt.
Im Allgemeinen ziehe ich es vor, den Job der Datenbank auf ein Minimum zu beschränken: "Diese Daten speichern, diese Daten abrufen". Es gibt jedoch immer Beispiele für Szenarien, in denen eine elegante Abfrage auf dem Server viel Bandbreite sparen kann.
Bedenken Sie auch: Wenn dies rechenintensiv ist, kann es irgendwo zwischengespeichert werden?
Wenn Sie ein genaues "was besser ist" wollen; codieren Sie es in beide Richtungen und vergleichen Sie es (wobei Sie feststellen, dass ein erster Entwurf von beiden wahrscheinlich nicht zu 100% abgestimmt ist). Berücksichtigen Sie jedoch die typische Verwendung: Wenn es in der Realität fünfmal (separat) gleichzeitig aufgerufen wird, simulieren Sie Folgendes: Vergleichen Sie nicht nur eine einzige "1 davon mit einer davon".
quelle
Lassen Sie mich eine Metapher verwenden: Wenn Sie in Paris eine goldene Halskette kaufen möchten , könnte der Goldschmied in Kapstadt oder Paris sitzen, das ist eine Frage des Könnens und des Geschmacks. Aber dafür würden Sie niemals Tonnen Golderz von Südafrika nach Frankreich liefern. Das Erz wird am Bergbaustandort (oder zumindest im allgemeinen Gebiet) verarbeitet, nur das Gold wird verschifft. Gleiches sollte für Apps und Datenbanken gelten.
Soweit PostgreSQL Bezug auf können Sie fast alles auf dem Server sehr effizient ausführen. Das RDBMS zeichnet sich durch komplexe Abfragen aus. Für prozedurale Anforderungen können Sie aus einer Vielzahl von serverseitigen Skriptsprachen auswählen: tcl, python, perl und viele mehr. Meistens benutze ich jedoch PL / pgSQL .
Das schlimmste Szenario wäre, wiederholt für jede einzelne Zeile eines größeren Satzes zum Server zu gehen. (Das wäre so, als würde man eine Tonne Erz pro Zeit versenden.)
Zweitens , wenn Sie eine Kaskade von Abfragen senden, die jeweils von der vorherigen abhängen, während alles in einer Abfrage oder Prozedur auf dem Server ausgeführt werden kann. (Das ist so, als würde man das Gold und jedes der Juwelen nacheinander mit einem separaten Schiff versenden.)
Das Hin- und Herwechseln zwischen App und Server ist teuer. Für Server und Client. Versuchen Sie, dies zu reduzieren, und Sie werden gewinnen: Verwenden Sie bei Bedarf serverseitige Prozeduren und / oder hochentwickeltes SQL.
Wir haben gerade ein Projekt abgeschlossen, in dem wir fast alle komplexen Abfragen in Postgres-Funktionen gepackt haben. Die App übergibt Parameter und erhält die benötigten Datensätze. Schnell, sauber, einfach (für den App-Entwickler), E / A auf ein Minimum reduziert ... eine glänzende Halskette mit geringem CO2-Ausstoß.
quelle
In diesem Fall ist es wahrscheinlich etwas besser, die Berechnung in SQL durchzuführen, da das Datenbankmodul wahrscheinlich über effizientere Dezimalarithmetikroutinen verfügt als Java.
Im Allgemeinen gibt es jedoch für Berechnungen auf Zeilenebene keinen großen Unterschied.
Wo es einen Unterschied macht, ist:
quelle
Es gibt kein Schwarz / Weiß darüber, welche Teile der Datenzugriffslogik in SQL ausgeführt werden sollen und welche Teile in Ihrer Anwendung ausgeführt werden sollen. Ich mag Mark Gravells Formulierung, die zwischen unterscheidet
Die Leistungsfähigkeit und Ausdruckskraft von SQL wird stark unterschätzt. Seit der Einführung von Fensterfunktionen können viele nicht streng satzorientierte Berechnungen sehr einfach und elegant in der Datenbank durchgeführt werden.
Unabhängig von der gesamten Anwendungsarchitektur sollten immer drei Faustregeln befolgt werden:
Nach meiner Erfahrung werden Sie mit einem anständigen DBA und einigen anständigen Kenntnissen über Ihre anständige Datenbank nicht sehr bald auf die CPU-Grenzwerte Ihrer DBs stoßen.
Einige weiterführende Literatur, in der diese Dinge erklärt werden:
quelle
Machen Sie im Allgemeinen Dinge in SQL, wenn die Möglichkeit besteht, dass auch andere Module oder Komponenten in demselben oder anderen Projekten diese Ergebnisse erzielen müssen. Eine atomare Operation, die serverseitig ausgeführt wird, ist auch besser, da Sie nur den gespeicherten Prozess von einem beliebigen Datenbankverwaltungstool aus aufrufen müssen, um endgültige Werte ohne weitere Verarbeitung zu erhalten.
In einigen Fällen trifft dies nicht zu, aber wenn dies der Fall ist, ist dies sinnvoll. auch im allgemeinen hat die db box die beste hardware und leistung.
quelle
Wenn Sie über ORM schreiben oder gelegentliche Anwendungen mit geringer Leistung schreiben, verwenden Sie ein beliebiges Muster, um die Anwendung zu vereinfachen. Wenn Sie eine Hochleistungsanwendung schreiben und sorgfältig über die Skalierung nachdenken, gewinnen Sie, indem Sie die Verarbeitung auf Daten verlagern. Ich empfehle nachdrücklich, die Verarbeitung auf die Daten zu verlagern.
Lassen Sie uns dies in zwei Schritten betrachten: (1) OLTP-Transaktionen (kleine Anzahl von Datensätzen). (2) OLAP (lange Scans vieler Datensätze).
Wenn Sie im OLTP-Fall schnell sein möchten (10.000 - 100.000 Transaktionen pro Sekunde), müssen Sie Latch-, Lock- und Dead-Lock-Konflikte aus der Datenbank entfernen. Dies bedeutet, dass Sie lange Verzögerungen bei Transaktionen vermeiden müssen: Roundtrips vom Client zur Datenbank, um die Verarbeitung auf den Client zu verschieben, sind eine solche lange Verzögerung. Sie können keine langlebigen Transaktionen (um das Lesen / Aktualisieren atomar zu machen) und keinen sehr hohen Durchsatz haben.
Betreff: horizontale Skalierung. Moderne Datenbanken werden horizontal skaliert. Diese Systeme implementieren bereits HA und Fehlertoleranz. Nutzen Sie das und versuchen Sie, Ihren Anwendungsbereich zu vereinfachen.
Schauen wir uns OLAP an - in diesem Fall sollte es offensichtlich sein, dass es eine schreckliche Idee ist, möglicherweise Terrabyte an Daten zurück in die Anwendung zu ziehen. Diese Systeme wurden speziell für den äußerst effizienten Betrieb mit komprimierten, vororganisierten Säulendaten entwickelt. Moderne OLAP-Systeme lassen sich auch horizontal skalieren und verfügen über ausgefeilte Abfrageplaner, die die Arbeit horizontal verteilen (interne Verarbeitung der Verarbeitung auf Daten).
quelle
Ob Berechnungen am Frontend oder am Backend durchgeführt werden sollen, ist sehr wichtig, wenn wir unser Ziel bei der Geschäftsimplementierung bestimmen können. Zur Zeit ist Java-Code möglicherweise leistungsfähiger als ein gut geschriebener SQL-Code oder umgekehrt. Aber immer noch, wenn Sie verwirrt sind, können Sie versuchen, zuerst festzustellen -
Es gibt viele andere Aspekte, über die Sie nachdenken können, bevor Sie entscheiden, wo der Code platziert werden soll. Eine Wahrnehmung ist völlig falsch - Alles kann am besten in Java (App-Code) und / oder alles am besten in der Datenbank (SQL-Code) ausgeführt werden.
quelle
Aus Sicht der Leistung: Dies ist eine sehr einfache arithmetische Operation, die mit ziemlicher Sicherheit viel schneller ausgeführt werden kann als das tatsächliche Abrufen der Daten von den Datenträgern, die der Datenbank zugrunde liegen. Außerdem ist es wahrscheinlich, dass die Berechnung der Werte in der where-Klausel zu jeder Laufzeit sehr schnell ist. Zusammenfassend sollte der Engpass die Festplatten-E / A sein, nicht die Berechnung der Werte.
Aus Gründen der Lesbarkeit denke ich, wenn Sie ein ORM verwenden, sollten Sie dies in Ihrer App-Server-Umgebung tun, da Sie mit dem ORM sehr einfach mit den zugrunde liegenden Daten arbeiten können, indem Sie satzbasierte Operationen verwenden. Wenn Sie ohnehin unformatiertes SQL schreiben möchten, ist die Berechnung dort nicht falsch. Ihr SQL würde auch ein wenig besser aussehen und leichter zu lesen sein, wenn es richtig formatiert wird.
quelle
Entscheidend ist, dass "Leistung" nicht definiert ist.
Das, was mir am wichtigsten ist, ist die Entwicklerzeit.
Schreiben Sie die SQL-Abfrage. Wenn es zu langsam ist oder die Datenbank zu einem Engpass wird, überdenken Sie es erneut. Zu diesem Zeitpunkt können Sie die beiden Ansätze vergleichen und Ihre Entscheidung auf der Grundlage realer Daten treffen, die für Ihr Setup relevant sind (Hardware und der Stapel, auf dem Sie sich befinden).
quelle
Ich glaube nicht, dass die Leistungsunterschiede ohne spezifische Beispiele und Benchmarks begründet werden können, aber ich habe eine andere Sichtweise:
Welches können Sie besser pflegen? Beispielsweise möchten Sie möglicherweise Ihr Front-End von Java auf Flash, HTML5, C ++ oder etwas anderes umstellen. Eine große Anzahl von Programmen hat eine solche Änderung durchlaufen oder existiert zunächst sogar in mehr als einer Sprache, da sie auf mehreren Geräten arbeiten müssen.
Selbst wenn Sie eine richtige mittlere Ebene haben (aus dem angegebenen Beispiel scheint dies nicht der Fall zu sein), kann sich diese Ebene ändern und JBoss wird möglicherweise zu Ruby / Rails.
Andererseits ist es unwahrscheinlich, dass Sie das SQL-Backend durch etwas ersetzen, das keine relationale Datenbank mit SQL ist, und selbst wenn Sie dies tun, müssen Sie das Front-End ohnehin von Grund auf neu schreiben, sodass der Punkt umstritten ist.
Meine Idee ist, dass es bei Berechnungen in der Datenbank viel einfacher ist, später ein zweites Front-End oder eine zweite Ebene zu schreiben, da Sie nicht alles neu implementieren müssen. In der Praxis denke ich jedoch, dass "wo kann ich dies mit Code tun, den die Leute verstehen werden" der wichtigste Faktor ist.
quelle
Um die Beantwortung zu vereinfachen, müsste der Lastausgleich betrachtet werden. Sie möchten die Last dort platzieren, wo Sie die größte Kapazität haben (wenn dies sinnvoll ist). In den meisten Systemen wird der SQL Server schnell zu einem Engpass. Die Antwort lautet wahrscheinlich, dass SQL nicht eine Unze mehr Arbeit leisten soll als nötig.
In den meisten Architekturen sind es auch die SQL Server, die den Kern des Systems bilden, und externe Systeme, die hinzugefügt werden.
Aber die obige Mathematik ist so trivial, dass der beste Ort, an dem Sie es platzieren können, der Ort ist, an dem Sie es platzieren möchten, es sei denn, Sie bringen Ihr System an seine Grenzen. Wenn die Mathematik nicht trivial wäre, wie beispielsweise die Berechnung von sin / cos / tan für beispielsweise eine Entfernungsberechnung, könnte der Aufwand nicht trivial werden und eine sorgfältige Planung und Prüfung erfordern.
quelle
Die anderen Antworten auf diese Frage sind interessant. Überraschenderweise hat niemand Ihre Frage beantwortet. Sie fragen sich:
Weitere Informationen: Bei Frage 1 möchten Sie sicherstellen, dass die Aggregation der Brüche ohne Rundungsfehler funktioniert. Ich denke, die Zahl 19,2 ist für Geld angemessen und im zweiten Fall sind die ganzen Zahlen in Ordnung. Die Verwendung eines Floats für Geld ist aus diesem Grund falsch.
Bei Frage zwei möchte ich als Programmierer die volle Kontrolle darüber haben, welches Datum als "jetzt" gilt. Bei Verwendung von Funktionen wie now () kann es schwierig sein, automatische Komponententests zu schreiben. Wenn Sie ein längeres Transaktionsskript haben, kann es auch sinnvoll sein, eine Variable auf now () zu setzen und die Variable so zu verwenden, dass die gesamte Logik genau denselben Wert verwendet.
quelle
Lassen Sie mich ein reales Beispiel nehmen, um diese Frage zu beantworten
Ich musste einen gewichteten gleitenden Durchschnitt für meine Ohlc-Daten berechnen. Ich habe ungefähr 134000 Kerzen mit einem Symbol für jede, um dies zu tun
Welches ist besser?
Bedarf
Um Sie zu ermutigen, ist dies die Python-Version, um einen gewichteten gleitenden Durchschnitt zu erstellen
WMA erfolgt über Code
WMA durch SQL
Ob Sie es glauben oder nicht, die Abfrage wird schneller ausgeführt als die Pure Python-Version eines WEIGHTED MOVING AVERAGE !!! Ich habe Schritt für Schritt diese Abfrage geschrieben, also bleib dran und du wirst es gut machen
Geschwindigkeit
0,42141127300055814 Sekunden Python
0,23801879299935536 Sekunden SQL
Ich habe 134000 gefälschte OHLC-Datensätze in meiner Datenbank, die auf 1000 Aktien aufgeteilt sind. Dies ist ein Beispiel dafür, wo SQL Ihren App-Server übertreffen kann
quelle