En bref, je serais d'accord avec votre CTO. Vous avez probablement gagné en performances au détriment de l'évolutivité (si ces termes prêtent à confusion, je vais clarifier ci-dessous). Mes deux plus gros soucis seraient la maintenabilité et le manque d'options pour évoluer horizontalement (en supposant que vous en aurez besoin).
Proximité des données: prenons du recul. Il y a de bonnes raisons de pousser du code dans une base de données. Je dirais que le plus important serait la proximité des données - par exemple, si vous vous attendez à ce qu'un calcul renvoie une poignée de valeurs, mais ce sont des agrégations de millions d'enregistrements, envoyant les millions d'enregistrements (à la demande) sur le réseau à agréger ailleurs est extrêmement coûteux et pourrait tuer facilement votre système. Cela dit, vous pouvez atteindre cette proximité des données par d'autres moyens, essentiellement en utilisant des caches ou des bases de données d'analyse où une partie de l'agrégation est effectuée en amont.
Performance du code dans la base de données:Les effets secondaires sur les performances, tels que la «mise en cache des plans d'exécution», sont plus difficiles à argumenter. Parfois, les plans d'exécution mis en cache peuvent être très négatifs si le mauvais plan d'exécution a été mis en cache. En fonction de votre SGBDR, vous pouvez tirer le meilleur parti de ceux-ci, mais vous n'obtiendrez pas beaucoup sur SQL paramétré, dans la plupart des cas (ces plans sont généralement mis en cache aussi). Je dirais également que la plupart des langages compilés ou JIT fonctionnent généralement mieux que leurs équivalents SQL (tels que T-SQL ou PL / SQL) pour les opérations de base et la programmation non relationnelle (manipulation de chaînes, boucles, etc.), vous ne le feriez donc pas ne perdez rien là-bas, si vous avez utilisé quelque chose comme Java ou C # pour faire le calcul des nombres. L'optimisation à grain fin est également assez difficile - sur la base de données, vous ' Nous sommes souvent coincés avec un arbre B générique (index) comme seule structure de données. Pour être juste, une analyse complète, y compris des choses comme des transactions plus longues, l'escalade des verrous, etc., pourrait remplir les livres.
Maintenabilité: SQL est un langage merveilleux pour ce qu'il a été conçu pour faire. Je ne suis pas sûr que ce soit un bon choix pour la logique d'application. La plupart des outils et des pratiques qui rendent nos vies supportables (TDD, refactoring, etc.) sont difficiles à appliquer à la programmation de bases de données.
Performance versus évolutivité:Pour clarifier ces termes, je veux dire ceci: la performance est la vitesse à laquelle vous vous attendez à ce qu'une seule demande passe par votre système (et revienne à l'utilisateur), pour le moment en supposant une faible charge. Cela sera souvent limité par des choses comme le nombre de couches physiques traversées, la façon dont ces couches sont optimisées, etc. L'évolutivité est la façon dont les performances changent avec l'augmentation du nombre d'utilisateurs / charge. Vous pouvez avoir des performances moyennes / faibles (disons, 5 secondes + pour une demande), mais une évolutivité impressionnante (capable de prendre en charge des millions d'utilisateurs). Dans votre cas, vous obtiendrez probablement de bonnes performances, mais votre évolutivité sera limitée par la taille d'un serveur que vous pouvez construire physiquement. À un moment donné, vous atteindrez cette limite et serez obligé de vous tourner vers des choses comme le partage, ce qui peut ne pas être possible selon la nature de l'application.
Optimisation prématurée: En fin de compte, je pense que vous avez fait l'erreur d'optimiser prématurément. Comme d'autres l'ont souligné, vous n'avez pas vraiment de mesures montrant comment les autres approches fonctionneraient. Eh bien, nous ne pouvons pas toujours construire des prototypes à grande échelle pour prouver ou réfuter une théorie ... Mais en général, j'hésiterais toujours à choisir une approche qui échange la maintenabilité (probablement la qualité la plus importante d'une application) pour la performance .
EDIT: Sur une note positive, la mise à l'échelle verticale peut s'étendre assez loin dans certains cas. Autant que je sache, SO a fonctionné sur un seul serveur pendant un certain temps. Je ne sais pas comment cela correspond à vos 10 000 utilisateurs (je suppose que cela dépend de la nature de ce qu'ils font dans votre système), mais cela vous donne une idée de ce qui peut être fait (en fait, il y a loin des exemples plus impressionnants, il se trouve que c'est un populaire que les gens peuvent facilement comprendre).
EDIT 2: Pour clarifier et commenter quelques points soulevés ailleurs:
- Re: Cohérence atomique - La cohérence ACID pourrait bien être une exigence du système. Ce qui précède ne contredit pas vraiment cela, et vous devez vous rendre compte que la cohérence ACID ne vous oblige pas à exécuter toute votre logique métier à l'intérieur de la base de données. En déplaçant du code qui n'a pas besoin d'être présent dans la base de données, vous le contraignez à s'exécuter dans l'environnement physique du reste de la base de données - il est en concurrence pour les mêmes ressources matérielles que la partie de gestion des données réelle de votre base de données. En ce qui concerne la mise à l'échelle uniquement du code vers d'autres serveurs de base de données (mais pas les données réelles) - bien sûr, cela peut être possible , mais que gagnez-vous exactement ici, à part les coûts de licence supplémentaires dans la plupart des cas? Gardez les choses qui n'ont pas besoin d'être sur la base de données, hors de la base de données.
- Re: Performances SQL / C # - puisque cela semble être un sujet d'intérêt, ajoutons un peu à la discussion. Vous pouvez certainement exécuter du code natif / Java / C # à l'intérieur des bases de données, mais pour autant que je sache, ce n'est pas ce qui a été discuté ici - nous comparons l'implémentation du code d'application typique dans quelque chose comme T-SQL à quelque chose comme C #. Il y a un certain nombre de problèmes qui ont été difficiles à résoudre avec le code relationnel dans le passé - par exemple, considérez le problème du "nombre maximal de connexions simultanées", où vous avez des enregistrements indiquant une connexion ou une déconnexion, et l'heure, et vous devez déterminer ce que le le nombre maximum d'utilisateurs connectés à un moment donné était. La solution la plus simple possible consiste à parcourir les enregistrements et à continuer à incrémenter / décrémenter un compteur lorsque vous rencontrez des connexions / déconnexions, et à garder une trace du maximum de cette valeur.mai, Je ne sais pas), le mieux que vous puissiez faire est un CURSEUR (les solutions purement relationnelles sont toutes sur des ordres de complexité différents, et tenter de le résoudre en utilisant une boucle while entraîne des performances moins bonnes). Dans ce cas, oui, la solution C # est en fait plus rapide que ce que vous pouvez obtenir en T-SQL, point. Cela peut sembler farfelu, mais ce problème peut facilement se manifester dans les systèmes financiers, si vous travaillez avec des lignes représentant des changements relatifs et devez calculer des agrégations fenêtrées sur ceux-ci. Les invocations de proc stockées ont également tendance à être plus coûteuses - invoquez un SP trivial un million de fois et voyez comment cela se compare à l'appel d'une fonction C #. J'ai fait allusion à quelques autres exemples ci-dessus - je n'ai encore rencontré personne implémenter une table de hachage appropriée en T-SQL (une qui donne en fait certains avantages), alors que c'est assez facile à faire en C #. Encore une fois, il y a des choses dans lesquelles les bases de données sont géniales et des choses qui ne le sont pas. Tout comme je ne voudrais pas faire de JOIN, SUM et GROUP BY en C #, je ne veux rien écrire de particulièrement gourmand en CPU dans T-SQL.