web-dev-qa-db-fra.com

"Ne faites jamais dans le code ce que vous pouvez faire pour que le serveur SQL fonctionne bien" - Est-ce une recette pour une mauvaise conception?

C'est une idée que j'ai entendue se répéter dans une poignée d'endroits. Certains reconnaissent plus ou moins qu'une fois que vous essayez de résoudre un problème purement en SQL dépasse un certain niveau de complexité, vous devez en effet le gérer en code.

La logique derrière l'idée est que pour la grande majorité des cas, le moteur de base de données fera un meilleur travail pour trouver le moyen le plus efficace d'accomplir votre tâche que vous ne pourriez en code. Surtout quand il s'agit de choses comme subordonner les résultats aux opérations effectuées sur les données. Sans doute avec des moteurs modernes JIT'ing + mise en cache efficace de la version compilée de votre requête, cela aurait du sens à la surface.

La question est de savoir si tirer parti de votre moteur de base de données de cette manière est intrinsèquement une mauvaise pratique de conception (et pourquoi). Les lignes deviennent encore plus floues lorsque toute la logique existe à l'intérieur de la base de données et que vous la frappez simplement via un ORM.

209
PhonicUK

Dans les mots du profane:

Ce sont des choses que SQL est fait pour faire et, croyez-le ou non, j'ai vu fait dans le code:

  • jointures - au niveau du code, cela nécessiterait une manipulation complexe des tableaux
  • filtrage des données (où) - au niveau du code, il faudrait insérer et supprimer des éléments dans les listes
  • sélection des colonnes - au niveau du code, cela nécessiterait une manipulation lourde des listes ou des tableaux
  • fonctions d'agrégation - au niveau du code, il faudrait des tableaux pour contenir des valeurs et des cas de commutation complexes
  • intégrité de la clé étrangère - selon le code, il faudrait des requêtes avant l'insertion et suppose que personne n'utilisera les données en dehors de l'application
  • intégrité de la clé primaire - selon le code, il faudrait des requêtes avant l'insertion et suppose que personne n'utilisera les données en dehors de l'application

Faire ces choses au lieu de s'appuyer sur SQL ou le SGBDR conduit à écrire des tonnes de code sans valeur ajoutée, ce qui signifie plus de code à déboguer et à maintenir. Et cela suppose dangereusement que la base de données ne sera accessible que via l'application.

325
Tulains Córdova

Je reformulerais cela en "Ne faites jamais dans le code ce que SQL Server peut faire pour vous enfin".

Des choses comme la manipulation de chaînes, le travail regex et ce que je ne ferais pas dans SQL Server (sauf SQL CLR).

Ce qui précède a tendance à parler de choses comme - les jointures, les opérations de définition et les requêtes. L'intention derrière cela est de déléguer une grande partie du travail lourd à SQL Server (dans les choses où il est bon) et de réduire la quantité de IO autant que possible (alors laissez SQL faire les jointures et filtrer avec une clause WHERE, renvoyant un ensemble de données beaucoup plus petit qu'autrement).

123
Oded

Ne faites jamais dans le code ce que vous pouvez faire faire au serveur SQL enfin pour vous (c'est moi qui souligne)

La clé de la réponse est que vous devez rechercher SQL qui fait quelque chose de bien, plutôt que de simplement faire quelque chose pour vous. SQL est un langage incroyablement puissant. Couplé avec des fonctions intégrées, il peut potentiellement faire beaucoup de choses. Cependant, le fait que vous puissiez faire quelque chose en SQL ne devrait pas être une excuse pour le faire réellement en SQL.

Mon critère spécifique pour prendre une décision est d'examiner la quantité de données que vous récupérez et le nombre d'aller-retour: si vous pouvez réduire la quantité de données en expédiant une tâche au serveur, sans augmenter le nombre d'arrondis- se déclenche, puis la tâche appartient au serveur; si la quantité de données reste la même ou augmente sans une baisse simultanée du nombre d'aller-retour, la tâche appartient à votre code.

Considérez ces exemples:

  • Vous stockez une date de naissance et vous devez calculer l'âge d'un groupe d'utilisateurs. Vous pouvez demander à SQL Server de faire la soustraction, ou vous pouvez le faire dans votre code. Le nombre d'aller-retour reste le même et la quantité de données qui vous est renvoyée augmente. Par conséquent, une solution basée sur le code gagne
  • Vous stockez une date de naissance et vous devez rechercher des utilisateurs âgés de 20 à 30 ans. Vous pouvez charger tous les utilisateurs sur le client, effectuer la soustraction pour trouver l'âge, puis filtrer, mais en envoyant la logique à SQL Server permettrait de réduire la quantité de données sans nécessiter un aller-retour supplémentaire; par conséquent, la solution basée sur SQL gagne.
47
dasblinkenlight

En bref , il serait correct de dire que: "Ne jamais effectuer opérations spécifiques à la base de données dans votre base de code "car elles sont mieux traitées dans votre base de données.

Regardez l'exemple des opérations de base . Comme vous le savez peut-être, [~ # ~] rdbms [~ # ~] sont construits pour gérer un stockage de données commun et opérations de manipulation.

De plus, le choix du projet de base de données joue un rôle important . Avoir un SGBDR (MS SQL, Oracle, etc.) est différent des bases de données NoSQL comme RavenDB.

22
Yusubov

En règle générale, votre base de données dispose de plus d'informations que votre application et peut effectuer des opérations de données courantes plus efficacement. Votre base de données conserve des index, par exemple, tandis que votre application devrait indexer les résultats de la recherche à la volée. Donc, toutes choses étant égales par ailleurs, votre charge de travail globale peut être réduite en poussant le travail vers la base de données plutôt que vers l'application.

Mais à mesure que votre produit évolue, il devient généralement plus facile de faire évoluer votre application que de faire évoluer votre base de données. Dans les grandes installations, il n'est pas rare de voir les serveurs d'applications plus nombreux que les serveurs de bases de données par un facteur de 10 à 1 ou plus. L'ajout de serveurs d'applications supplémentaires est souvent une simple question de clonage d'un serveur existant sur un nouveau matériel. En revanche, l'ajout de nouveaux serveurs de base de données est considérablement plus difficile dans la plupart des cas.

Donc, à ce stade, le mantra devient protéger la base de données. Il s'avère qu'en mettant la base de données en cache dans memcached ou en mettant en file d'attente les mises à jour dans un journal côté application, ou en récupérant les données une fois et en calculant vos statistiques dans votre application, vous pouvez réduire considérablement la charge de travail de votre base de données, en économisant de devoir recourir à une configuration de cluster DB encore plus compliquée et fragile.

13
tylerl

Je pense que ce serait une mauvaise conception de ne pas utiliser la base de données pour les choses auxquelles elle est destinée. Je n'ai jamais vu de base de données où les règles ont été appliquées en dehors de la base de données contenant de bonnes données. Et j'ai regardé des centaines de bases de données.

Donc, les choses qui doivent être faites dans une base de données:

  • Audit (l'audit d'application uniquement ne suivra pas toutes les modifications apportées à la base de données et ne vaut donc rien).

  • Contraintes d'ingerité des données, y compris les valeurs par défaut, les contraintes de clé étrangère et les règles qui doivent toujours être appliquées à toutes les données. Toutes les données ne sont pas toujours modifiées ou insérées via une application, il existe des correctifs de données ponctuels, en particulier pour les grands ensembles de données qui ne sont pas pratiques pour effectuer un enregistrement à la fois (veuillez mettre à jour ces 100000 enregistrements qui ont été confondus avec le statut 1 quand ils devraient be 2 en raison d'un bogue de code d'application ou veuillez mettre à jour tous les enregistrements du client A vers le client B car la société B a acheté la société A) et les importations de données et d'autres applications pouvant toucher la même base de données.

  • JOINS et filtrage de la clause where (pour réduire le nombre d'enregistrements envoyés sur le réseau)

12
HLGEM

"L'optimisation prématurée est la racine de tous les maux (la plupart de toute façon) dans la programmation informatique" - Donald Knuth

La base de données est exactement cela; la couche de données de votre application. Son rôle est de fournir à votre application les données demandées et de stocker les données qui lui sont transmises. Votre application est l'endroit où mettre du code qui fonctionne réellement avec les données; l'afficher, le valider, etc.

Alors que le sentiment dans la ligne de titre est admirable et précis jusqu'à un certain point (l'essentiel du filtrage, de la projection, du regroupement, etc. devrait dans le nombre écrasant de cas être laissé à la DB), une définition de "bien" pourrait être en ordre. Les tâches que SQL Server peut exécuter avec un haut niveau de performances sont nombreuses, mais les tâches que vous pouvez démontrer que SQL Server exécute correctement de manière isolée et répétable sont très peu nombreuses. SQL Management Studio est une excellente base de données IDE (surtout compte tenu des autres options avec lesquelles j'ai travaillé comme TOAD), mais elle a ses limites, la première d'entre elles étant à peu près tout ce que vous utilisez pour faire (ou tout code de procédure que vous exécutez dans la base de données située en dessous) est par définition un "effet secondaire" (altération de l’état en dehors du domaine de l’espace mémoire de votre processus). De plus, le code de procédure dans SQL Server n’est les derniers IDE et outils, pouvant être mesurés de la manière dont le code managé peut utiliser les mesures de couverture et l'analyse de chemin (vous pouvez donc démontrer que cette instruction if particulière est rencontrée par les tests X, Y et Z, et que le test X est conçu pour créer la condition true et exécutez cette moitié pendant que Y et Z exécutent le "else". Cela, à son tour, suppose que vous avez un test qui peut configurer la base de données avec un état de départ particulier, exécuter le code procédural de la base de données par une action et affirmer l'attendu résultats.

Tout cela est beaucoup plus difficile et impliqué que la solution fournie par la plupart des couches d'accès aux données; Supposons que la couche de données (et, en l'occurrence, le DAL) sache comment faire son travail lorsqu'elle reçoit la bonne entrée, puis testez que votre code fournit une entrée correcte. En gardant le code procédural comme les SP et les déclencheurs hors de la base de données et au lieu de faire ces types de choses dans le code d'application, ledit code d'application est beaucoup plus facile à exercer.

6
KeithS

Une des choses que les gens ne semblent pas réaliser est que faire tout votre traitement sur le serveur SQL n'est pas nécessairement bon, quels que soient les effets sur la qualité du code.

Par exemple, si vous devez récupérer des données, puis calculer quelque chose à partir des données, puis stocker ces données dans la base de données. Il y a deux choix:

  • Saisissez les données dans votre application, calculez dans votre application, puis renvoyez les données à la base de données
  • Créez une procédure stockée ou similaire pour récupérer les données, effectuez un calcul sur celles-ci, puis stockez le tout à partir d'un seul appel vers le serveur SQL.

Vous pensez peut-être que la deuxième solution est toujours la plus rapide, mais ce n'est certainement pas vrai. J'ignore même si SQL est un mauvais ajustement pour le problème (ie regex et manipulation de chaînes). Imaginons que vous ayez SQL CLR ou quelque chose de similaire pour avoir même un langage puissant dans la base de données. S'il faut 1 seconde pour faire un aller-retour et obtenir les données et 1 seconde pour les stocker, puis 10 secondes pour effectuer le calcul à travers. Vous vous trompez si vous faites tout dans la base de données.

Bien sûr, vous vous rasez 2 secondes. Cependant, avez-vous plutôt gaspillé 100% (au moins) d'un cœur de processeur sur votre serveur de base de données pendant 10 secondes, ou avez-vous plutôt perdu ce temps sur votre serveur Web?

Les serveurs Web sont faciles à mettre à l'échelle, les bases de données, en revanche, sont extrêmement coûteuses, en particulier les bases de données SQL. La plupart du temps, les serveurs Web sont également "sans état" et peuvent être ajoutés et supprimés à volonté, sans configuration supplémentaire à part l'équilibreur de charge.

Alors, pensez non seulement à raser 2 secondes d'une opération, mais pensez également à l'évolutivité. Pourquoi gaspiller une ressource coûteuse comme les ressources du serveur de base de données lorsque vous pouvez utiliser les ressources du serveur Web beaucoup moins chères avec un impact relativement faible sur les performances

5
Earlz

J'aime le regarder car SQL ne devrait traiter que les données elles-mêmes. Les règles métier qui déterminent l'apparence de la requête peuvent se produire dans le code. La regex ou la validation de l'informaiton doit se faire en code. Il faut laisser SQL pour simplement rejoindre votre table, interroger vos données, insérer des données propres, etc.

Ce qui est transmis à SQL doit être des données propres et SQL ne doit pas vraiment avoir besoin de plus que ce dont il a besoin pour le stocker, le mettre à jour, le supprimer ou récupérer quelque chose. J'ai vu beaucoup trop de développeurs vouloir jeter leur logique métier et leur codage en SQL car ils considèrent les données comme leur métier. Découpez votre logique de vos données et vous constaterez que votre code devient plus propre et plus facile à gérer.

Juste mon 0,02 $ cependant.

4
Stanley Glass Jr

En général, je suis d'accord que le code doit contrôler la logique métier et la base de données doit être un hachage sans logique. Mais voici quelques contre-points:

La clé primaire, la clé étrangère et les contraintes requises (non nulles) peuvent être appliquées par le code. Les contraintes sont la logique métier. Doivent-ils être exclus de la base de données car ils reproduisent ce que le code peut faire?

D'autres parties indépendantes de votre volonté touchent-elles la base de données? Si oui, avoir des contraintes imposées à proximité des données est Nice. L'accès peut être limité à un service Web qui implémente une logique, mais cela suppose que vous étiez là "en premier" et que vous avez le pouvoir d'imposer l'utilisation du service aux autres parties.

Votre ORM effectue-t-il une insertion/mise à jour distincte pour chaque objet? Si oui, vous rencontrerez de graves problèmes de performances lors du traitement par lots de grands ensembles de données. Définir les opérations est la voie à suivre. Un ORM aura du mal à modéliser avec précision tous les ensembles joints possibles sur lesquels vous pourriez effectuer des opérations.

Considérez-vous qu'une "couche" est une division physique par les serveurs ou une division logique? L'exécution de la logique sur n'importe quel serveur pourrait théoriquement rester sous sa couche logique. Vous pouvez organiser le fractionnement en compilant dans différentes DLL plutôt qu'en fractionnant exclusivement les serveurs. Cela peut considérablement augmenter le temps de réponse (mais sacrifier le débit) tout en maintenant la séparation des préoccupations. Un split DLL pourrait plus tard être déplacé vers d'autres serveurs sans nouvelle construction pour augmenter le débit (au prix du temps de réponse).

3
mike30

L'idiome est davantage lié au maintien des règles métier, aux données, ainsi qu'aux relations (les données et la structure et les relations.) Ce n'est pas un guichet unique pour chaque problème, mais cela permet d'éviter des choses comme manuellement compteurs d'enregistrements maintenus, intégrité des relations gérée manuellement, etc., si ces éléments sont disponibles au niveau de la base de données. Donc, si quelqu'un d'autre arrive et étend les programmes ou écrit un autre programme qui interagit avec la base de données, il n'aura pas à comprendre comment maintenir l'intégrité de la base de données à partir du code précédent. Le cas d'un compteur d'enregistrements géré manuellement est particulièrement pertinent lorsque quelqu'un d'autre veut créer un nouveau programme pour interagir avec la même base de données. Même si le programme nouvellement créé a exactement le bon code pour le compteur, le programme d'origine et le nouveau qui s'exécutent à peu près en même temps sont susceptibles de le corrompre. Il existe même du code qui récupère les enregistrements et vérifie les conditions avant d'écrire un nouvel enregistrement ou une mise à jour (dans le code ou sous forme de requêtes distinctes), lorsque cela est possible si possible souvent directement dans l'instruction d'insertion ou de mise à jour. Une corruption des données peut à nouveau en résulter. Le moteur de base de données garantit l'atomicité; une mise à jour ou une requête d'insertion avec conditions est garantie d'affecter uniquement les enregistrements remplissant les conditions et aucune requête externe ne peut modifier les données à mi-chemin de notre mise à jour. Il existe de nombreuses autres circonstances où le code est utilisé lorsque le moteur de base de données serait mieux utilisé. Tout dépend de l'intégrité des données et non des performances.

C'est donc en fait un bon idiome de conception ou une règle d'or. Aucune performance ne va aider dans un système avec des données corrompues.

3
Chris

Il y a quelques points à retenir:

  • Une base de données relationnelle doit garantir l'intégrité référentielle via des clés étrangères
  • La mise à l'échelle d'une base de données peut être difficile et coûteuse. La mise à l'échelle d'un serveur Web est beaucoup plus facile simplement en ajoutant plus de serveurs Web. Amusez-vous en essayant d'ajouter plus de puissance au serveur SQL.
  • Avec C # et LINQ, vous pouvez faire vos "jointures" et ainsi de suite par le biais du code afin de tirer le meilleur parti des deux mondes dans de nombreux cas
0
Joe Phillips

Comme mentionné précédemment, l'objectif est d'envoyer et de recevoir le moins possible de la base de données car les allers-retours sont très coûteux en temps. L'envoi répété de requêtes SQL est une perte de temps, en particulier dans les requêtes plus complexes.

L'utilisation de procédures stockées dans la base de données permet aux développeurs d'interagir avec la base de données comme une API, sans se soucier du schéma complexe à l'arrière. Cela réduit également les données envoyées au serveur car seul le nom et quelques paramètres sont envoyés. Dans ce scénario, la plupart des logiques bussines peuvent toujours être dans le code mais pas sous forme de SQL. Le code préparerait essentiellement ce qui doit être envoyé ou demandé à la base de données.

0
Laurent Goderre

"L'optimisation prématurée est la racine de tout mal" - Donald Knuth

Utilisez l'outil le plus approprié pour le travail. Pour l'intégrité des données, il s'agit souvent de la base de données. Pour les règles métier avancées, il s'agit d'un système basé sur des règles comme JBoss Drools. Pour la visualisation des données, ce serait un cadre de rapport. etc.

Si vous rencontrez des problèmes de performances, vous devez ensuite vérifier si des données peuvent être mises en cache ou si une implémentation dans la base de données serait plus rapide. En général, le coût d'achat de serveurs supplémentaires ou d'une puissance cloud supplémentaire sera bien inférieur au coût de maintenance supplémentaire et à l'impact des bogues supplémentaires.

0
parasietje