Je sais que les procédures stockées sont plus efficaces via le chemin d'exécution (que le sql en ligne dans les applications). Cependant, une fois pressé, je ne sais pas trop pourquoi.
Je voudrais connaître le raisonnement technique pour cela (d'une manière que je puisse expliquer à quelqu'un plus tard).
Quelqu'un peut-il m'aider à formuler une bonne réponse?
Réponses:
Je crois que ce sentiment était vrai à un moment donné, mais pas dans les versions actuelles de SQL Server. Tout le problème était que dans le passé, les instructions SQL ad hoc ne pouvaient pas être correctement optimisées car SQL Server ne pouvait qu'optimiser / compiler au niveau du lot. Nous avons maintenant une optimisation au niveau de l'instruction, donc une requête correctement paramétrée provenant d'une application peut bénéficier du même plan d'exécution que cette requête incorporée dans une procédure stockée.
Je préfère toujours les procédures stockées du côté DBA pour les raisons suivantes (et plusieurs d'entre elles peuvent avoir un impact énorme sur les performances):
sys.sql_modules
pour les références à des objets spécifiques) rend la vie de chacun beaucoup plus facile.SET ANSI_WARNINGS ON
, et l'autre pourrait avoirSET ANSI_WARNINGS OFF
, et ils auraient chacun leur propre copie du plan. Le plan qu'ils obtiennent dépend des paramètres utilisés, des statistiques en place, etc. la première fois que la requête est appelée dans chaque cas, ce qui peut conduire à des plans différents et donc à des performances très différentes.Cela dit, cette question est susceptible de susciter plus d'arguments religieux qu'un débat technique. Si nous voyons cela se produire, nous le fermerons probablement.
la source
Bien que je respecte l'auteur de la communication, je suis humblement en désaccord avec la réponse fournie et non pour des "raisons religieuses". En d'autres termes, je crois que Microsoft n'a fourni aucune installation qui diminue le besoin de conseils pour utiliser les procédures stockées.
Toute directive fournie à un développeur qui favorise l'utilisation de requêtes SQL en texte brut doit être remplie de nombreuses mises en garde, de sorte que je pense que le conseil le plus prudent est d'encourager considérablement l'utilisation des procédures stockées et de décourager vos équipes de développeurs de s'engager dans la pratique. d'incorporer des instructions SQL dans le code, ou de soumettre des requêtes SQL brutes, en texte brut, en dehors des SPROC SQL (procédures stockées).
Je pense que la réponse simple à la question de savoir pourquoi utiliser un SPROC est celle du soumissionnaire: les SPROC sont analysés, optimisés et compilés. En tant que tels, leurs plans de requête / d'exécution sont mis en cache car vous avez enregistré une représentation statique d'une requête et vous ne la modifierez normalement que par des paramètres, ce qui n'est pas vrai dans le cas d'instructions SQL copiées / collées qui se transforment probablement de page en page et de composant / niveau, et sont souvent variablisés dans la mesure où différentes tables, même des noms de base de données, peuvent être spécifiés d'appel à appel. Permettre ce type de dynamique ad hocLa soumission SQL réduit considérablement la probabilité que le moteur DB réutilise le plan de requête pour vos instructions ad hoc, selon certaines règles très strictes. Ici, je fais la distinction entre les requêtes dynamiques ad hoc (dans l'esprit de la question posée) par rapport à l'utilisation du système SPROC sp_executesql efficace.
Plus précisément, il existe les composants suivants:
Lorsqu'une instruction SQL est émise à partir d'une page Web, appelée «instruction ad hoc», le moteur recherche un plan d'exécution existant pour gérer la demande. Comme il s'agit d'un texte soumis par un utilisateur, il sera ingéré, analysé, compilé et exécuté, s'il est valide. À ce moment, il recevra un coût de requête de zéro. Le coût de la requête est utilisé lorsque le moteur de base de données utilise son algorithme afin de déterminer les plans d'exécution à expulser du cache.
Les requêtes ad hoc reçoivent une valeur de coût de requête d'origine de zéro, par défaut. Lors de l'exécution ultérieure du même texte de requête ad hoc exact, par un autre processus utilisateur (ou le même), le coût de la requête actuelle est réinitialisé au coût de compilation d'origine. Étant donné que notre coût de compilation de requêtes ad hoc est nul, cela n'augure rien de bon pour la possibilité de réutilisation. Évidemment, zéro est l'entier le moins valorisé, mais pourquoi serait-il expulsé?
Lorsque des pressions de mémoire surviennent, et ce sera le cas si vous avez un site souvent utilisé, le moteur de base de données utilise un algorithme de nettoyage pour déterminer comment il peut récupérer la mémoire utilisée par le cache de procédures. Il utilise le coût de requête actuel pour décider des plans à expulser. Comme vous pouvez le deviner, les plans avec un coût de zéro sont les premiers à être expulsés du cache car zéro signifie essentiellement «aucun utilisateur actuel ou référence à ce plan».
Par conséquent, il est tout à fait probable qu'un tel plan sera expulsé en premier lorsque des pressions de mémoire surviendront.
Par conséquent, si vous disposez d'un serveur avec beaucoup de mémoire "au-delà de vos besoins", vous ne rencontrerez peut-être pas ce problème aussi souvent qu'un serveur occupé qui ne dispose que de mémoire "suffisante" pour gérer sa charge de travail. (Désolé, la capacité et l'utilisation de la mémoire du serveur sont quelque peu subjectives / relatives, bien que l'algorithme ne le soit pas.)
Maintenant, si je me trompe sur un ou plusieurs points, je suis certainement prêt à être corrigé.
Enfin, l'auteur a écrit:
"Nous avons maintenant une optimisation au niveau de l'instruction, de sorte qu'une requête correctement paramétrée provenant d'une application peut tirer parti du même plan d'exécution que cette requête incorporée dans une procédure stockée."
Je pense que l'auteur fait référence à l'option "Optimiser pour les charges de travail ad hoc".
Si tel est le cas, cette option permet un processus en deux étapes qui évite d'envoyer immédiatement le plan de requête complet au cache de procédure. Il n'envoie qu'un stub de requête plus petit. Si un appel de requête exact est renvoyé vers le serveur alors que le talon de requête est toujours dans le cache de procédure, le plan d'exécution de requête complet est enregistré dans le cache de procédure, à ce moment. Cela économise de la mémoire qui, lors d'incidents de pression de la mémoire, peut permettre à l'algorithme d'éviction d'expulser votre talon moins fréquemment qu'un plan de requête plus grand qui a été mis en cache. Encore une fois, cela dépend de la mémoire et de l'utilisation de votre serveur.
Cependant, vous devez activer cette option, car elle est désactivée par défaut.
Enfin, je tiens à souligner que, souvent, la raison même pour laquelle les développeurs intègrent SQL dans des pages, des composants et d'autres emplacements, c'est parce qu'ils souhaitent être flexibles et soumettre une requête SQL dynamique au moteur de base de données. Par conséquent, dans un cas d'utilisation réel, la soumission du même texte, appel sur appel, est peu susceptible de se produire, tout comme la mise en cache / l'efficacité que nous recherchons, lors de la soumission de requêtes ad hoc à SQL Server.
Pour plus d'informations, veuillez consulter:
https://technet.microsoft.com/en-us/library/ms181055(v=sql.105).aspx
http://sqlmag.com/database-performance-tuning/don-t-fear-dynamic-sql
Bien,
Henry
la source
TLDR: Il n'y a pas de différence de performance appréciable entre les deux tant que votre sql inline est paramétré.
Voici la raison pour laquelle j'ai progressivement supprimé les procédures stockées:
Nous exécutons un environnement d'application «bêta» - un environnement parallèle à la production qui partage la base de données de production. Étant donné que le code db se situe au niveau de l'application et que les modifications de la structure db sont rares, nous pouvons permettre aux utilisateurs de confirmer de nouvelles fonctionnalités au-delà du contrôle qualité et d'effectuer des déploiements en dehors de la fenêtre de déploiement de la production tout en fournissant des fonctionnalités de production et des correctifs non critiques. Cela ne serait pas possible si la moitié du code d'application se trouvait dans la base de données.
Nous pratiquons les devops au niveau de la base de données (octopus + dacpacs). Cependant, alors que la couche métier et les versions ultérieures peuvent être purgées et remplacées et la récupération juste à l'inverse, cela n'est pas vrai pour les modifications incrémentielles et potentiellement destructrices qui doivent être apportées aux bases de données. Par conséquent, nous préférons garder nos déploiements DB plus légers et moins fréquents.
Afin d'éviter des copies presque exactes du même code pour les paramètres facultatifs, nous utilisons souvent un modèle «où @var est nul ou @ var = table.field». Avec un proc stocké, vous obtiendrez probablement le même plan d'exécution, malgré des intentions plutôt différentes, et donc rencontrez des problèmes de performances ou éliminez les plans mis en cache avec des astuces de «recompilation». Cependant, avec un simple bout de code qui ajoute un commentaire "signature" à la fin du sql, nous pouvons forcer différents plans en fonction des variables qui étaient nulles (ne pas être interprété comme un plan différent pour toutes les combinaisons de variables - seulement nul vs non nul).
Je peux apporter des changements spectaculaires aux résultats avec seulement des changements mineurs à la volée au sql. Par exemple, je peux avoir une déclaration qui se termine avec deux CTE, "Raw" et "ReportReady". Il n'y a rien qui dit que les deux CTE doivent être utilisés Ma déclaration sql peut alors être:
...
sélectionnez * parmi {(format)} "
Cela me permet d'utiliser exactement la même méthode de logique métier pour un appel API simplifié et un rapport qui doit être plus détaillé en veillant à ne pas dupliquer une logique compliquée.
Il existe des raisons valables d'utiliser procs:
Sécurité - Vous avez ici une autre couche sur laquelle l'application doit passer. Si le compte du service d'application n'est pas autorisé à toucher les tables, mais ne dispose que de l'autorisation «exécuter» sur les procs, vous bénéficiez d'une protection supplémentaire. Cela n'en fait pas une donnée car cela a un coût, mais c'est une possibilité.
Réutilisation - Bien que je dirais que la réutilisation devrait se produire en grande partie au niveau de la couche métier pour s'assurer que vous ne contournez pas les règles métier non liées à la base de données, nous avons toujours le type occasionnel de bas niveau "utilisé partout" de procs et fonctions utilitaires.
Il y a quelques arguments qui ne prennent pas vraiment en charge les procs ou qui sont facilement atténués par l'OMI:
Réutilisation - J'ai mentionné cela ci-dessus comme un "plus", mais je voulais également mentionner ici que la réutilisation devrait se produire en grande partie au niveau de l'entreprise. Un processus pour insérer un enregistrement ne doit pas être considéré comme "réutilisable" lorsque la couche métier peut également vérifier d'autres services non-db.
Cache plan balloat - la seule façon que cela va être un problème est si vous concaténez des valeurs plutôt que de paramétrer. Le fait que vous obtenez rarement plus d'un plan par proc vous fait souvent du mal lorsque vous avez un «ou» dans une requête
Taille de l'instruction - un kb supplémentaire d'instructions sql sur le nom de proc va généralement être négligeable par rapport aux données qui reviennent. Si c'est ok pour les Entités, c'est ok pour moi.
Voir la requête exacte - Rendre les requêtes faciles à trouver dans le code est aussi simple que d'ajouter l'emplacement d'appel en tant que commentaire au code. Rendre le code copiable du code c # vers ssms est aussi simple qu'une certaine interpolation créative et une utilisation des commentaires:
Sql Injection - Paramétrez vos requêtes. Terminé. Cela peut en fait être annulé si le proc utilise à la place SQL dynamique.
Contournement du déploiement - Nous pratiquons également les devops au niveau de la base de données, ce n'est donc pas une option pour nous.
"Lent dans l'application, rapide dans SSMS" - Il s'agit d'un problème de mise en cache du plan qui affecte les deux côtés. Les options définies provoquent simplement la compilation d'un nouveau plan qui semble résoudre le problème des variables THE ONE SET OFF. Cela ne fait que répondre à la raison pour laquelle vous voyez des résultats différents - les options définies elles-mêmes ne résolvent PAS le problème du reniflage des paramètres.
Les plans d'exécution SQL en ligne ne sont pas mis en cache - simplement faux. Une instruction paramétrée, tout comme le nom du proc, est rapidement hachée, puis un plan est recherché par ce hachage. C'est 100% pareil.
Pour être clair, je parle de code SQL brut en ligne non généré à partir d'un ORM - nous utilisons uniquement Dapper qui est au mieux un micro ORM.
https://weblogs.asp.net/fbouma/38178
/programming//a/15277/852208
la source