it-swarm.com.de

"Machen Sie niemals im Code, was der SQL Server für Sie gut machen kann" - Ist dies ein Rezept für ein schlechtes Design?

Es ist eine Idee, die ich an einigen Stellen wiederholt gehört habe. Einige erkennen mehr oder weniger an, dass Sie, sobald Sie versuchen, ein Problem nur in SQL zu lösen, einen bestimmten Grad an Komplexität überschreiten, es tatsächlich im Code behandeln sollten.

Die Logik hinter der Idee ist, dass die Datenbank-Engine in den meisten Fällen besser daran arbeitet, den effizientesten Weg zur Ausführung Ihrer Aufgabe zu finden, als Sie es im Code könnten. Insbesondere, wenn es darum geht, die Ergebnisse von Operationen abhängig zu machen, die an den Daten ausgeführt werden. Mit modernen Engines, die die kompilierte Version Ihrer Abfrage effektiv JIT'ing + Caching durchführen, wäre dies an der Oberfläche sinnvoll.

Die Frage ist, ob die Nutzung Ihrer Datenbank-Engine auf diese Weise von Natur aus eine schlechte Entwurfspraxis ist (und warum). Die Linien verschwimmen weiter, wenn die gesamte Logik in der Datenbank vorhanden ist und Sie sie nur über ein ORM treffen.

209
PhonicUK

In Laienwörtern :

Dies sind Dinge, die SQL ist dafür gemacht und ob Sie es glauben oder nicht, ich habe im Code gesehen:

  • Joins - Codeweise würde es eine komplexe Array-Manipulation erfordern
  • Filtern von Daten (wo) - Codeweise würde das umfangreiche Einfügen und Löschen von Elementen in Listen erforderlich sein
  • Spalten auswählen - Codeweise würde es eine umfangreiche Listen- oder Array-Manipulation erfordern
  • Aggregatfunktionen - Codeweise wären Arrays erforderlich, um Werte und komplexe Switch-Fälle zu speichern
  • Fremdschlüsselintegrität - Codeweise wären vor dem Einfügen Abfragen erforderlich, und es wird davon ausgegangen, dass niemand die Daten außerhalb der App verwendet
  • Primärschlüsselintegrität - Codeweise wären vor dem Einfügen Abfragen erforderlich, und es wird davon ausgegangen, dass niemand die Daten außerhalb der App verwendet

Wenn Sie diese Dinge tun, anstatt sich auf SQL oder das RDBMS zu verlassen führt dazu, dass Sie Tonnen von Code ohne Mehrwert schreiben, was bedeutet, dass mehr Code debuggt und gewartet werden muss. Und es wird gefährlich davon ausgegangen, dass auf die Datenbank nur über die Anwendung zugegriffen wird.

325

Ich würde das umformulieren zu "Niemals im Code tun, was SQL Server für Sie tun kann gut".

Dinge wie String-Manipulation, Regex-Arbeit und dergleichen würde ich in SQL Server nicht tun (außer SQL CLR).

Das Obige neigt dazu, über Dinge wie - Joins, Set-Operationen und Abfragen zu sprechen. Die Absicht dahinter ist, einen Großteil des schweren Hebens an SQL Server zu delegieren (in Dingen, in denen es gut ist) und die Menge an IO so weit wie möglich) zu reduzieren (also lassen Sie SQL die Joins und ausführen Filtern Sie mit einer WHERE -Klausel nach unten und geben Sie einen viel kleineren Datensatz zurück als sonst.

123
Oded

Tun Sie niemals im Code, was der SQL Server tun soll gut für Sie (Schwerpunkt liegt bei mir)

Der Schlüssel zur Antwort ist, dass Sie nach SQL suchen müssen, das etwas gut macht, anstatt einfach etwas für Sie zu tun. SQL ist eine erstaunlich mächtige Sprache. In Verbindung mit integrierten Funktionen kann es möglicherweise viele Dinge tun. Die Tatsache, dass Sie etwas in SQL tun können, sollte jedoch keine Entschuldigung dafür sein, es tatsächlich in SQL zu tun.

Meine spezifischen Kriterien für eine Entscheidung sind die Anzahl der Daten, die Sie zurückerhalten, und die Anzahl der Roundtrips: Wenn Sie die Datenmenge reduzieren können, indem Sie eine Aufgabe an den Server senden, ohne die Anzahl der Roundtrips zu erhöhen. Auslösungen, dann gehört die Aufgabe auf den Server; Wenn die Datenmenge gleich bleibt oder zunimmt, ohne dass gleichzeitig die Anzahl der Hin- und Rückfahrten abnimmt, gehört die Aufgabe in Ihren Code.

Betrachten Sie diese Beispiele:

  • Sie speichern ein Geburtsdatum und müssen das Alter für eine Gruppe von Benutzern berechnen. Sie können die Subtraktion von SQL Server ausführen lassen oder in Ihrem Code. Die Anzahl der Hin- und Rückfahrten bleibt gleich und die an Sie zurückgesendete Datenmenge steigt. Daher gewinnt eine codebasierte Lösung
  • Sie speichern ein Geburtsdatum und müssen Benutzer im Alter zwischen 20 und 30 Jahren finden. Sie können alle Benutzer wieder auf den Client laden, die Subtraktion durchführen, um das Alter zu ermitteln, und dann die Filterung durchführen, aber die Logik an SQL Server senden würde die Datenmenge reduzieren, ohne zusätzliche Hin- und Rückflüge zu erfordern; Daher gewinnt die SQL-basierte Lösung.
47
dasblinkenlight

Kurz gesagt wäre es richtig zu sagen: "Niemals durchführen datenbankspezifische Operationen in Ihrer Codebasis ", da sie in Ihrer Datenbank besser behandelt werden.

Schauen Sie sich ein Beispiel für die Set-Basisoperationen an. Wie Sie vielleicht wissen, werden [~ # ~] rdbms [~ # ~] erstellt, um einen gemeinsamen Datenspeicher zu handhaben und Manipulationsoperationen.

Darüber hinaus spielt die Projektauswahl der Datenbank eine wichtige Rolle . Ein RDBMS (MS SQL, Oracle usw.) unterscheidet sich von NoSQL-Datenbanken wie RavenDB.

22
Yusubov

In der Regel verfügt Ihre Datenbank über mehr Informationen als Ihre Anwendung und kann allgemeine Datenoperationen effizienter ausführen. Ihre Datenbank verwaltet beispielsweise Indizes, während Ihre Anwendung die Suchergebnisse im laufenden Betrieb indizieren müsste. Wenn alles andere gleich ist, kann Ihre Gesamtarbeitslast verringert werden, indem die Arbeit in die Datenbank und nicht in die Anwendung verschoben wird.

Wenn Ihr Produkt skaliert, ist es in der Regel einfacher, Ihre App zu skalieren, als Ihre Datenbank zu skalieren. Bei großen Installationen ist es nicht ungewöhnlich, dass Anwendungsserver die Datenbankserver um den Faktor 10 zu 1 oder mehr übertreffen. Das Hinzufügen weiterer Anwendungsserver ist häufig eine einfache Angelegenheit, einen vorhandenen Server auf neue Hardware zu klonen. Das Hinzufügen neuer Datenbankserver ist dagegen in den meisten Fällen erheblich schwieriger.

An diesem Punkt wird das Mantra also zu Datenbank schützen. Es stellt sich heraus, dass Sie durch Zwischenspeichern der Datenbankergebnisse in memcached oder durch Einreihen von Aktualisierungen in ein anwendungsseitiges Protokoll oder durch einmaliges Abrufen der Daten und Berechnen Ihrer Statistiken in Ihrer App die Datenbankauslastung drastisch reduzieren und sparen können Sie müssen nicht auf eine noch kompliziertere und fragilere DB-Cluster-Konfiguration zurückgreifen.

13
tylerl

Ich denke, es wäre ein schlechtes Design, die Datenbank nicht für die Dinge zu verwenden, für die sie bestimmt ist. Ich habe noch nie eine Datenbank gesehen, in der die Regeln außerhalb der Datenbank mit guten Daten durchgesetzt wurden. Und ich habe mir Hunderte von Datenbanken angesehen.

Also Dinge, die in einer Datenbank erledigt werden müssen:

  • Überwachung (nur die Anwendungsüberwachung verfolgt nicht alle Änderungen an der Datenbank und ist daher wertlos).

  • Dateningeritätsbeschränkungen, einschließlich Standardwerten, Fremdschlüsseleinschränkungen und Regeln, die immer auf alle Daten angewendet werden müssen. Alle Daten werden nicht immer über eine Anwendung geändert oder eingefügt. Es gibt einmalige Datenkorrekturen, insbesondere bei großen Datenmengen, bei denen es nicht praktikabel ist, jeweils einen Datensatz zu erstellen (bitte aktualisieren Sie diese 100.000 Datensätze, die als Status 1 nicht markiert wurden, wenn dies erforderlich ist aufgrund eines Anwendungscode-Fehlers 2 sein oder alle Datensätze von Client A auf Client B aktualisieren, da Unternehmen B Unternehmen A gekauft hat) sowie Datenimporte und andere Anwendungen, die möglicherweise dieselbe Datenbank berühren.

  • JOINS und where-Klauselfilterung (um die Anzahl der über das Netzwerk gesendeten Datensätze zu verringern)

12
HLGEM

"Vorzeitige Optimierung ist die Wurzel allen Übels (jedenfalls das meiste davon) in der Computerprogrammierung" - Donald Knuth

Die Datenbank ist genau das; die Datenschicht Ihrer Anwendung. Seine Aufgabe ist es, Ihrer Anwendung die angeforderten Daten zur Verfügung zu stellen und die ihr gegebenen Daten zu speichern. In Ihrer Anwendung können Sie Code einfügen, der tatsächlich mit den Daten funktioniert. Anzeigen, Validieren usw.

Während das Gefühl in der Titelzeile bewundernswert und bis zu einem gewissen Punkt genau ist (das Wesentliche beim Filtern, Projizieren, Gruppieren usw. sollte in der überwältigenden Anzahl von Fällen der DB überlassen werden), ist eine Definition von "gut" könnte in Ordnung sein. Es gibt viele Aufgaben, die SQL Server mit einem hohen Leistungsniveau ausführen kann, aber es gibt nur sehr wenige Aufgaben, die Sie demonstrieren ausführen können, die SQL Server isoliert und wiederholbar korrekt ausführt. SQL Management Studio ist eine großartige Datenbank IDE (insbesondere angesichts der anderen Optionen, mit denen ich wie TOAD gearbeitet habe), aber es hat seine Einschränkungen, unter anderem, dass es so ziemlich alles ist, wofür Sie es verwenden do (oder jeder prozedurale Code, den Sie in der darunter liegenden Datenbank ausführen) ist per Definition ein "Nebeneffekt" (Ändern des Status außerhalb der Domäne des Speicherbereichs Ihres Prozesses). Außerdem ist prozeduraler Code in SQL Server erst jetzt mit dem Neueste IDEs und Tools, die mithilfe von Abdeckungsmetriken und Pfadanalysen so gemessen werden können, wie verwalteter Code (so können Sie zeigen, dass diese bestimmte if-Anweisung bei den Tests X, Y und Z auftritt und Test X die Bedingung erfüllt true und führen Sie diese Hälfte aus, während Y und Z das "else" ausführen. Dies setzt wiederum voraus, dass Sie einen Test haben, der die Datenbank mit einem bestimmten Startzustand einrichten, den Datenbankprozedurcode durch eine Aktion ausführen und den erwarteten Wert bestätigen kann Ergebnisse.

All dies ist viel schwieriger und komplizierter als die Lösung, die von den meisten Datenzugriffsschichten bereitgestellt wird. Nehmen Sie an, dass die Datenschicht (und im Übrigen die DAL) weiß, wie sie ihre Arbeit erledigt, wenn sie die richtige Eingabe erhält, und testen Sie dann, ob Ihr Code die richtige Eingabe liefert. Indem prozeduraler Code wie SPs und Trigger aus der Datenbank herausgehalten werden und stattdessen diese Art von Dingen im Anwendungscode ausgeführt werden, ist der Anwendungscode viel einfacher zu üben.

6
KeithS

Eines der Dinge, die die Leute nicht zu bemerken scheinen, ist, dass die gesamte Verarbeitung auf dem SQL Server nicht unbedingt gut ist, unabhängig von den Auswirkungen auf die Codequalität.

Zum Beispiel, wenn Sie einige Daten abrufen und dann etwas aus den Daten berechnen und diese Daten dann in der Datenbank speichern müssen. Es gibt zwei Möglichkeiten:

  • Nehmen Sie die Daten in Ihre Anwendung auf, berechnen Sie sie in Ihrer Anwendung und senden Sie sie dann an die Datenbank zurück
  • Erstellen Sie eine gespeicherte Prozedur oder ähnliches, um die Daten abzurufen, zu berechnen und dann alles von einem einzelnen Aufruf an SQL Server zu speichern.

Sie mögen denken, dass die zweite Lösung immer die schnellste ist, aber das ist definitiv nicht wahr. Ich ignoriere, auch wenn SQL nicht für das Problem geeignet ist (dh Regex- und String-Manipulation). Stellen wir uns vor, Sie haben SQL CLR oder ähnliches, um sogar eine leistungsstarke Sprache in der Datenbank zu haben. Wenn es 1 Sekunde dauert, um eine Rundreise durchzuführen und die Daten abzurufen, und 1 Sekunde, um sie zu speichern, und dann 10 Sekunden, um die Berechnung darüber durchzuführen. Sie machen es falsch, wenn Sie alles in der Datenbank machen.

Klar, du rasierst dich 2 Sekunden ab. Haben Sie jedoch lieber 10 Sekunden lang 100% (mindestens) eines CPU-Kerns auf Ihrem Datenbankserver verschwendet, oder haben Sie diese Zeit lieber auf Ihrem Webserver verschwendet?

Webserver sind einfach zu skalieren, Datenbanken hingegen sind extrem teuer, insbesondere SQL-Datenbanken. Meistens sind Webserver auch "zustandslos" und können nach Belieben ohne zusätzliche Konfiguration zu etwas anderem als dem Load Balancer hinzugefügt und entfernt werden.

Denken Sie also nicht nur daran, eine Operation um 2 Sekunden zu verkürzen, sondern auch an die Skalierbarkeit. Warum sollten Sie eine teure Ressource wie Datenbankserverressourcen verschwenden, wenn Sie die viel billigeren Webserverressourcen mit relativ geringen Auswirkungen auf die Leistung verwenden können?

5
Earlz

Ich schaue es mir gerne an, da SQL nur mit den Daten selbst umgehen sollte. Die Geschäftsregeln, die entscheiden, wie die Abfrage aussehen soll, können im Code vorkommen. Die Regex oder Validierung der Informationen sollte im Code erfolgen. SQL sollte nur übrig bleiben, um Ihre Tabelle zu verbinden, Ihre Daten abzufragen, saubere Daten einzufügen usw.

Was an SQL übergeben wird, sollten saubere Daten sein, und SQL sollte eigentlich nichts mehr wissen müssen, als es speichern, aktualisieren, löschen oder etwas abrufen muss. Ich habe gesehen, dass viel zu viele Entwickler ihre Geschäftslogik und Codierung in SQL umwandeln möchten, weil sie die Daten als ihr Geschäft betrachten. Wenn Sie Ihre Logik von Ihren Daten entkoppeln, wird Ihr Code sauberer und einfacher zu verwalten.

Nur meine $ 0,02.

4

Im Allgemeinen stimme ich zu, dass der Code die Geschäftslogik steuern sollte und die DB ein logikfreier Hash sein sollte. Aber hier sind einige Gegenpunkte:

Primär-, Fremdschlüssel- und erforderliche (nicht null) Einschränkungen können durch Code erzwungen werden. Einschränkungen sind Geschäftslogik. Sollten sie aus der Datenbank ausgeschlossen werden, da sie duplizieren, was Code kann?

Berühren andere Parteien außerhalb Ihrer Kontrolle die Datenbank? Wenn dies der Fall ist, ist es hilfreich, Einschränkungen in der Nähe der Daten durchzusetzen. Der Zugriff könnte auf einen Webdienst beschränkt sein, der Logik implementiert. Dies setzt jedoch voraus, dass Sie "zuerst" dort waren und die Befugnis haben, die Nutzung des Dienstes für die anderen Parteien durchzusetzen.

Führt Ihr ORM für jedes Objekt eine separate Einfügung/Aktualisierung durch? Wenn ja, treten bei der Stapelverarbeitung großer Datenmengen schwerwiegende Leistungsprobleme auf. Set-Operationen sind der richtige Weg. Ein ORM hat Probleme, alle möglichen verbundenen Sätze, an denen Sie Operationen ausführen können, genau zu modellieren.

Betrachten Sie eine "Schicht" als physische Aufteilung nach Servern oder als logische Aufteilung? Das Ausführen von Logik auf einem beliebigen Server könnte theoretisch immer noch unter die logische Schicht fallen. Sie können die Aufteilung organisieren, indem Sie sie in verschiedene DLLs kompilieren, anstatt ausschließlich Server aufzuteilen. Dies kann die Reaktionszeit drastisch verlängern (aber den Durchsatz opfern), während die Trennung der Bedenken aufrechterhalten wird. Ein Split DLL könnte später ohne einen neuen Build auf andere Server verschoben werden, um den Durchsatz zu erhöhen (auf Kosten der Antwortzeit).

3
mike30

Die Redewendung hat mehr damit zu tun, die Geschäftsregeln beizubehalten, mit den Daten zusammen mit den Beziehungen (den Daten und der Struktur und den Beziehungen). Es ist nicht eine zentrale Anlaufstelle für jedes Problem, aber es hilft, Dinge wie manuell zu vermeiden gepflegte Datensatzzähler, manuell gepflegte Beziehungsintegrität usw., wenn diese Dinge auf Datenbankebene verfügbar sind. Wenn also jemand anderes vorbeikommt und die Programme erweitert oder ein anderes Programm schreibt, das mit der Datenbank interagiert, muss er nicht herausfinden, wie die Datenbankintegrität gegenüber dem vorherigen Code aufrechterhalten werden kann. Der Fall eines manuell verwalteten Datensatzzählers ist besonders relevant, wenn eine andere Person ein neues Programm für die Interaktion mit derselben Datenbank erstellen möchte. Selbst wenn das neu erstellte Programm genau den richtigen Code für den Zähler hat, können das ursprüngliche Programm und das neue Programm, die ungefähr zur gleichen Zeit ausgeführt werden, ihn wahrscheinlich beschädigen. Es gibt sogar Code, der Datensätze abruft und Bedingungen überprüft, bevor ein neuer oder aktualisierter Datensatz geschrieben wird (in Code oder als separate Abfragen). Wenn möglich, kann dies häufig direkt in der Einfüge- oder Aktualisierungsanweisung erreicht werden. Es kann erneut zu Datenbeschädigungen kommen. Die Datenbank-Engine garantiert Atomizität; Eine Aktualisierungs- oder Einfügeabfrage mit Bedingungen wirkt sich garantiert nur auf die Datensätze aus, die die Bedingungen erfüllen, und keine externe Abfrage kann die Daten in der Mitte unseres Updates ändern. Es gibt viele andere Umstände, unter denen Code verwendet wird, wenn das Datenbankmodul besser funktioniert. Es geht um Datenintegrität und nicht um Leistung.

Es ist also eigentlich eine gute Designsprache oder Faustregel. In einem System mit beschädigten Daten hilft keine Leistung.

3
Chris

Es gibt ein paar Dinge zu beachten:

  • Eine relationale Datenbank sollte die referenzielle Integrität durch Fremdschlüssel sicherstellen
  • Das Skalieren einer Datenbank kann schwierig und teuer sein. Das Skalieren eines Webservers ist viel einfacher, indem einfach mehr Webserver hinzugefügt werden. Viel Spaß beim Versuch, mehr SQL Server-Leistung hinzuzufügen.
  • Mit C # und LINQ können Sie Ihre "Joins" und so weiter über Code ausführen, sodass Sie in vielen Fällen das Beste aus beiden Welten erhalten
0
Joe Phillips

Wie bereits erwähnt, besteht das Ziel darin, so wenig wie möglich aus der Datenbank zu senden und von dieser zu empfangen, da die Hin- und Rückfahrten zeitlich sehr kostspielig sind. Das wiederholte Senden von SQL-Anweisungen ist Zeitverschwendung, insbesondere bei komplexeren Abfragen.

Durch die Verwendung gespeicherter Prozeduren in der Datenbank können Entwickler wie eine API mit der Datenbank interagieren, ohne sich um das komplexe Schema auf der Rückseite kümmern zu müssen. Es reduziert auch die an den Server gesendeten Daten, da nur der Name und einige Parameter gesendet werden. In diesem Szenario kann sich der größte Teil der Geschäftslogik noch im Code befinden, jedoch nicht in Form von SQL. Der Code würde im Wesentlichen vorbereiten, was von der Datenbank gesendet oder angefordert werden soll.

0
Laurent Goderre

"Vorzeitige Optimierung ist die Wurzel allen Übels" - Donald Knuth

Verwenden Sie das für den Job am besten geeignete Werkzeug. Für die Datenintegrität ist dies häufig die Datenbank. Für erweiterte Geschäftsregeln ist dies ein regelbasiertes System wie JBoss Drools. Für die Datenvisualisierung wäre dies ein Berichtsrahmen. usw.

Wenn Sie Leistungsprobleme haben, sollten Sie anschließend prüfen, ob Daten zwischengespeichert werden können oder ob eine Implementierung in der Datenbank schneller wäre. Im Allgemeinen sind die Kosten für den Kauf zusätzlicher Server oder zusätzlicher Cloud-Leistung weitaus niedriger als die zusätzlichen Wartungskosten und die Auswirkungen zusätzlicher Fehler.

0
parasietje