Kurz gesagt, ich stimme Ihrem CTO zu. Sie haben wahrscheinlich auf Kosten der Skalierbarkeit eine gewisse Leistung erzielt (wenn diese Begriffe verwirrend sind, erkläre ich dies weiter unten). Meine zwei größten Sorgen wären die Wartbarkeit und der Mangel an Optionen für die horizontale Skalierung (vorausgesetzt, Sie werden das brauchen).
Nähe zu Daten: Machen wir einen Schritt zurück. Es gibt einige gute Gründe, Code in eine Datenbank zu verschieben. Ich würde argumentieren, dass die größte Nähe zu den Daten besteht - zum Beispiel, wenn Sie erwarten, dass eine Berechnung eine Handvoll Werte zurückgibt, aber dies sind Aggregationen von Millionen von Datensätzen, die die Millionen von Datensätzen (bei Bedarf) übermitteln Das Netzwerk, das an anderer Stelle aggregiert werden muss, ist äußerst verschwenderisch und kann Ihr System leicht zum Erliegen bringen. Allerdings können Sie diese Nähe von Daten auch auf andere Weise erreichen, indem Sie im Wesentlichen Caches oder Analyse-DBs verwenden, bei denen ein Teil der Aggregation im Voraus erfolgt.
Leistung des Codes in der DB:Sekundäre Leistungseffekte wie "Zwischenspeichern von Ausführungsplänen" sind schwieriger zu diskutieren. Manchmal können zwischengespeicherte Ausführungspläne sehr negativ sein, wenn der falsche Ausführungsplan zwischengespeichert wurde. Abhängig von Ihrem RDBMS können Sie das meiste aus diesen herausholen, aber Sie werden in den meisten Fällen nicht viel über parametrisiertes SQL herausfinden (diese Pläne werden normalerweise auch zwischengespeichert). Ich würde auch argumentieren, dass die meisten kompilierten oder mit JIT erstellten Sprachen in der Regel eine bessere Leistung als ihre SQL-Entsprechungen (wie T-SQL oder PL / SQL) für grundlegende Operationen und nicht relationale Programmierung (Manipulation von Zeichenfolgen, Schleifen usw.) erbringen Sie verlieren dort nichts, wenn Sie etwas wie Java oder C # zum Knabbern der Zahlen verwenden. Feinkörnige Optimierung ist auch ziemlich schwierig - auf der DB, Sie Häufig wird ein generischer B-Baum (Index) als einzige Datenstruktur verwendet. Um fair zu sein, könnte eine vollständige Analyse, einschließlich längerer Transaktionen, Sperreneskalation usw., Bücher füllen.
Wartbarkeit: SQL ist eine wunderbare Sprache für das, wofür es entwickelt wurde. Ich bin mir nicht sicher, ob es gut zur Anwendungslogik passt. Die meisten Tools und Methoden, die unser Leben erträglich machen (TDD, Refactoring usw.), sind bei der Datenbankprogrammierung nur schwer anwendbar.
Leistung versus Skalierbarkeit:Um diese Begriffe zu verdeutlichen, meine ich Folgendes: Die Leistung gibt an, wie schnell eine einzelne Anforderung Ihr System (und zurück zum Benutzer) durchläuft, wenn nur eine geringe Auslastung angenommen wird. Dies wird oft durch Dinge wie die Anzahl der physischen Schichten, die durchlaufen werden, wie gut diese Schichten optimiert sind usw. begrenzt. Die Skalierbarkeit ist, wie sich die Leistung mit zunehmender Anzahl von Benutzern / Auslastung ändert. Möglicherweise verfügen Sie über eine mittlere / niedrige Leistung (z. B. 5 Sekunden + für eine Anforderung), aber eine hervorragende Skalierbarkeit (die Millionen von Benutzern unterstützen kann). In Ihrem Fall werden Sie wahrscheinlich eine gute Leistung erzielen, Ihre Skalierbarkeit wird jedoch davon abhängen, wie groß ein Server sein kann, den Sie physisch aufbauen können. Irgendwann werden Sie an diese Grenze stoßen und gezwungen sein, sich Dingen wie Scherben zuzuwenden, die je nach Art der Anwendung möglicherweise nicht durchführbar sind.
Vorzeitige Optimierung: Letztendlich haben Sie den Fehler gemacht, vorzeitig zu optimieren. Wie andere darauf hingewiesen haben, gibt es keine Messungen, die zeigen, wie die anderen Ansätze funktionieren würden. Nun, wir können nicht immer maßstabsgetreue Prototypen bauen, um eine Theorie zu beweisen oder zu widerlegen ... Aber im Allgemeinen würde ich immer zögern, einen Ansatz zu wählen, der Wartbarkeit (wahrscheinlich die wichtigste Qualität einer Anwendung) für die Leistung tauscht .
BEARBEITEN: Positiv ist zu vermerken, dass die vertikale Skalierung in einigen Fällen ziemlich weit gehen kann. Soweit ich weiß, lief SO einige Zeit auf einem einzelnen Server. Ich bin mir nicht sicher, wie es Ihren 10 000 Benutzern entspricht (ich denke, es hängt von der Art ab, wie sie in Ihrem System vorgehen), aber es gibt Ihnen eine Vorstellung davon, was getan werden kann (tatsächlich gibt es weit eindrucksvollere Beispiele, dies ist einfach ein beliebtes Beispiel, das die Leute leicht verstehen können).
EDIT 2: Um ein paar Dinge zu klären und zu kommentieren, die an anderer Stelle angesprochen wurden:
- Betreff: Atomare Konsistenz - Die ACID-Konsistenz kann durchaus eine Anforderung des Systems sein. Das oben Gesagte spricht nicht wirklich dagegen, und Sie sollten sich darüber im Klaren sein, dass die ACID-Konsistenz nicht erfordert, dass Sie Ihre gesamte Geschäftslogik in der Datenbank ausführen. Durch die Verschieben - Code, der nicht brauchte , dort zu sein in die DB, Sie beschränke es in der physischen Umgebung des Restes der DB zu laufen - es ist im Wettbewerb um die gleichen Hardware - Ressourcen als den eigentliche Datenverwaltung Teil Ihrer DB. Da es nur darum geht, den Code auf andere DB-Server (aber nicht auf die eigentlichen Daten) zu skalieren, ist dies zwar möglich , aber was genau erzielen Sie hier, abgesehen von den zusätzlichen Lizenzkosten in den meisten Fällen? Behalten Sie Dinge, die nicht in der DB sein müssen, außerhalb der DB.
- Betreff: SQL / C # -Leistung - da dies ein interessantes Thema zu sein scheint, wollen wir die Diskussion etwas erweitern. Natürlich können Sie nativen / Java / C # -Code in DBs ausführen, aber soweit ich weiß, wurde hier nicht darüber gesprochen. Wir vergleichen die Implementierung von typischem Anwendungscode in T-SQL mit der von C #. Es gibt eine Reihe von Problemen, die in der Vergangenheit mit relationalem Code nur schwer zu lösen waren - z. B. das Problem "Maximale Anzahl gleichzeitiger Anmeldungen", bei dem Aufzeichnungen vorliegen, die eine Anmeldung oder Abmeldung sowie die Uhrzeit angeben Die maximale Anzahl der gleichzeitig angemeldeten Benutzer war. Die einfachste mögliche Lösung besteht darin, die Datensätze zu durchlaufen und einen Zähler weiter zu erhöhen / zu verringern, wenn Anmeldungen / Abmeldungen auftreten, und das Maximum dieses Werts zu protokollieren.kannIch weiß nicht), das Beste, was Sie tun können, ist ein CURSOR (die rein relationalen Lösungen sind alle unterschiedlich komplex, und der Versuch, sie mit einer while-Schleife zu lösen, führt zu einer schlechteren Leistung). In diesem Fall ist die C # -Lösung tatsächlich schneller als das, was Sie in T-SQL erreichen können. Das mag weit hergeholt erscheinen, aber dieses Problem kann sich leicht in Finanzsystemen manifestieren, wenn Sie mit Zeilen arbeiten, die relative Änderungen darstellen, und fensterorientierte Aggregationen für diese berechnen müssen. Gespeicherte Proc-Aufrufe sind in der Regel auch teurer. Rufen Sie eine einfache SP millionenfach auf und sehen Sie, wie sich dies mit dem Aufrufen einer C # -Funktion vergleichen lässt. Ich habe oben einige andere Beispiele angedeutet - ich habe noch niemanden angetroffen, der eine richtige Hash-Tabelle in T-SQL implementiert hat (eine, die tatsächlich einige Vorteile bietet), während dies in C # ziemlich einfach ist. Wieder gibt es Dinge, bei denen DBs großartig sind, und Dinge, bei denen sie nicht so großartig sind. So wie ich JOINs, SUMs und GROUP BYs nicht in C # ausführen möchte, möchte ich in T-SQL nichts besonders CPU-intensives schreiben.